user profile

This commit is contained in:
Flatlogic Bot 2026-03-22 03:18:19 +00:00
parent 5e776c9e2b
commit 6387f7c226
13 changed files with 428 additions and 96 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1 @@
ALTER TABLE users ADD COLUMN avatar VARCHAR(255) DEFAULT NULL;

View File

@ -269,18 +269,21 @@ $site_favicon = !empty($site_settings['company_favicon']) ? $site_settings['comp
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#topNav"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#topNav">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse" id="topNav"> <div class="collapse navbar-collapse justify-content-end" id="topNav">
<div class="ms-auto d-flex align-items-center"> <div class="d-flex align-items-center">
<a href="?lang=<?php echo get_lang_code(); ?>" class="btn btn-outline-secondary btn-sm me-3"> <a href="?lang=<?php echo get_lang_code(); ?>" class="btn btn-outline-secondary btn-sm me-3">
<i class="bi bi-translate"></i> <?php echo get_lang_name(); ?> <i class="bi bi-translate"></i> <?php echo get_lang_name(); ?>
</a> </a>
<div class="dropdown"> <div class="dropdown">
<a class="nav-link dropdown-toggle d-flex align-items-center" href="#" role="button" data-bs-dropdown="dropdown"> <a class="nav-link dropdown-toggle d-flex align-items-center" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<img src="https://ui-avatars.com/api/?name=<?php echo urlencode($current_user['name']); ?>&background=0056b3&color=fff" class="rounded-circle me-2" width="32" height="32"> <?php
$user_avatar = !empty($current_user['avatar']) ? $current_user['avatar'] : "https://ui-avatars.com/api/?name=" . urlencode($current_user['name']) . "&background=0056b3&color=fff";
?>
<img src="<?php echo htmlspecialchars($user_avatar); ?>" class="rounded-circle me-2" width="32" height="32" style="object-fit: cover;">
<span><?php echo htmlspecialchars($current_user['name']); ?></span> <span><?php echo htmlspecialchars($current_user['name']); ?></span>
</a> </a>
<ul class="dropdown-menu dropdown-menu-end shadow border-0"> <ul class="dropdown-menu dropdown-menu-end shadow border-0">
<li><a class="dropdown-item" href="#"><i class="bi bi-person me-2"></i> <?php echo __('profile'); ?> (<?php echo htmlspecialchars($current_user['role_slug']); ?>)</a></li> <li><a class="dropdown-item" href="profile.php"><i class="bi bi-person me-2"></i> <?php echo __('profile'); ?> (<?php echo htmlspecialchars($current_user['role_slug']); ?>)</a></li>
<li><hr class="dropdown-divider"></li> <li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item text-danger" href="logout.php"><i class="bi bi-box-arrow-right me-2"></i> <?php echo __('logout'); ?></a></li> <li><a class="dropdown-item text-danger" href="logout.php"><i class="bi bi-box-arrow-right me-2"></i> <?php echo __('logout'); ?></a></li>
</ul> </ul>

View File

@ -6,7 +6,7 @@
<h3 class="fw-bold text-secondary"><?php echo __('appointments'); ?></h3> <h3 class="fw-bold text-secondary"><?php echo __('appointments'); ?></h3>
<div> <div>
<button class="btn btn-outline-secondary shadow-sm me-2" onclick="printAppointments()"> <button class="btn btn-outline-secondary shadow-sm me-2" onclick="printAppointments()">
<i class="bi bi-printer me-1"></i> Print Daily List <i class="bi bi-printer me-1"></i> <?php echo __('print_daily_list'); ?>
</button> </button>
<button class="btn btn-primary shadow-sm" onclick="showCreateModal()"> <button class="btn btn-primary shadow-sm" onclick="showCreateModal()">
<i class="bi bi-calendar-plus me-1"></i> <?php echo __('book_appointment'); ?> <i class="bi bi-calendar-plus me-1"></i> <?php echo __('book_appointment'); ?>
@ -19,7 +19,7 @@
<div class="card-body"> <div class="card-body">
<div class="row g-3"> <div class="row g-3">
<div class="col-md-4"> <div class="col-md-4">
<label class="form-label small text-muted"><?php echo __('doctor'); ?> (Filter)</label> <label class="form-label small text-muted"><?php echo __('doctor'); ?> (<?php echo __('filter'); ?>)</label>
<select id="doctorFilter" class="form-select bg-light"> <select id="doctorFilter" class="form-select bg-light">
<option value=""><?php echo __('all'); ?> <?php echo __('doctors'); ?></option> <option value=""><?php echo __('all'); ?> <?php echo __('doctors'); ?></option>
<?php foreach ($all_doctors as $d): ?> <?php foreach ($all_doctors as $d): ?>
@ -31,19 +31,19 @@
<div class="d-flex align-items-end h-100 pb-1 flex-wrap"> <div class="d-flex align-items-end h-100 pb-1 flex-wrap">
<div class="d-flex align-items-center me-3 mb-2"> <div class="d-flex align-items-center me-3 mb-2">
<div class="badge bg-primary me-2" style="width: 15px; height: 15px; border-radius: 50%;">&nbsp;</div> <div class="badge bg-primary me-2" style="width: 15px; height: 15px; border-radius: 50%;">&nbsp;</div>
<small class="text-muted">Scheduled</small> <small class="text-muted"><?php echo __('scheduled'); ?></small>
</div> </div>
<div class="d-flex align-items-center me-3 mb-2"> <div class="d-flex align-items-center me-3 mb-2">
<div class="badge bg-success me-2" style="width: 15px; height: 15px; border-radius: 50%;">&nbsp;</div> <div class="badge bg-success me-2" style="width: 15px; height: 15px; border-radius: 50%;">&nbsp;</div>
<small class="text-muted">Completed</small> <small class="text-muted"><?php echo __('completed'); ?></small>
</div> </div>
<div class="d-flex align-items-center me-3 mb-2"> <div class="d-flex align-items-center me-3 mb-2">
<div class="badge bg-danger me-2" style="width: 15px; height: 15px; border-radius: 50%;">&nbsp;</div> <div class="badge bg-danger me-2" style="width: 15px; height: 15px; border-radius: 50%;">&nbsp;</div>
<small class="text-muted">Cancelled</small> <small class="text-muted"><?php echo __('cancelled'); ?></small>
</div> </div>
<div class="d-flex align-items-center me-3 mb-2"> <div class="d-flex align-items-center me-3 mb-2">
<div class="badge me-2" style="width: 15px; height: 15px; border-radius: 50%; background-color: #fd7e14;">&nbsp;</div> <div class="badge me-2" style="width: 15px; height: 15px; border-radius: 50%; background-color: #fd7e14;">&nbsp;</div>
<small class="text-muted">Home Visit</small> <small class="text-muted"><?php echo __('home_visits'); ?></small>
</div> </div>
<div class="d-flex align-items-center mb-2"> <div class="d-flex align-items-center mb-2">
<div class="badge bg-warning me-2" style="width: 15px; height: 15px; border-radius: 50%;">&nbsp;</div> <div class="badge bg-warning me-2" style="width: 15px; height: 15px; border-radius: 50%;">&nbsp;</div>
@ -66,7 +66,7 @@
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content border-0 shadow"> <div class="modal-content border-0 shadow">
<div class="modal-header border-0 pb-0"> <div class="modal-header border-0 pb-0">
<h5 class="modal-title fw-bold text-secondary" id="modalTitle">Appointment Details</h5> <h5 class="modal-title fw-bold text-secondary" id="modalTitle"><?php echo __('appointment_details'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body pt-3"> <div class="modal-body pt-3">
@ -89,10 +89,10 @@
</select> </select>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label small text-muted">Provider Type</label> <label class="form-label small text-muted"><?php echo __('provider'); ?></label>
<select id="apt_provider_type" class="form-select" onchange="toggleProviderField()"> <select id="apt_provider_type" class="form-select" onchange="toggleProviderField()">
<option value="Doctor">Doctor</option> <option value="Doctor"><?php echo __('doctor'); ?></option>
<option value="Nurse">Nurse</option> <option value="Nurse"><?php echo __('nurse'); ?></option>
</select> </select>
</div> </div>
</div> </div>
@ -105,7 +105,7 @@
<div class="mb-3" id="div_doctor"> <div class="mb-3" id="div_doctor">
<label class="form-label small text-muted"><?php echo __('doctor'); ?></label> <label class="form-label small text-muted"><?php echo __('doctor'); ?></label>
<select id="apt_doctor_id" class="form-select select2-modal-apt"> <select id="apt_doctor_id" class="form-select select2-modal-apt">
<option value="">Select Doctor</option> <option value=""><?php echo __('select_doctor'); ?></option>
<?php foreach ($all_doctors as $d): ?> <?php foreach ($all_doctors as $d): ?>
<option value="<?php echo $d['id']; ?>"><?php echo htmlspecialchars($d['name']); ?></option> <option value="<?php echo $d['id']; ?>"><?php echo htmlspecialchars($d['name']); ?></option>
<?php endforeach; ?> <?php endforeach; ?>
@ -130,9 +130,9 @@
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
<label class="form-label small text-muted"><?php echo __('status'); ?></label> <label class="form-label small text-muted"><?php echo __('status'); ?></label>
<select id="apt_status" class="form-select"> <select id="apt_status" class="form-select">
<option value="Scheduled">Scheduled</option> <option value="Scheduled"><?php echo __('scheduled'); ?></option>
<option value="Completed">Completed</option> <option value="Completed"><?php echo __('completed'); ?></option>
<option value="Cancelled">Cancelled</option> <option value="Cancelled"><?php echo __('cancelled'); ?></option>
</select> </select>
</div> </div>
</div> </div>
@ -234,7 +234,7 @@ function validateHolidayFrontend() {
} }
if (isHoliday) { if (isHoliday) {
$('<div id="holidayWarning" class="alert alert-warning mt-3 mb-0 small"><i class="bi bi-exclamation-triangle"></i> Selected doctor is on holiday on this date.</div>').appendTo('#appointmentDetailsModal .modal-body'); $('<div id="holidayWarning" class="alert alert-warning mt-3 mb-0 small"><i class="bi bi-exclamation-triangle"></i> <?php echo __('doctor_is_on_holiday_on_this_date'); ?></div>').appendTo('#appointmentDetailsModal .modal-body');
if (btnSave) btnSave.disabled = true; if (btnSave) btnSave.disabled = true;
} else { } else {
if (btnSave) btnSave.disabled = false; if (btnSave) btnSave.disabled = false;
@ -447,7 +447,7 @@ document.addEventListener('DOMContentLoaded', function() {
eventClick: function(info) { eventClick: function(info) {
if (info.event.extendedProps.type === 'appointment') { if (info.event.extendedProps.type === 'appointment') {
var props = info.event.extendedProps; var props = info.event.extendedProps;
document.getElementById('modalTitle').innerText = 'Edit Appointment'; document.getElementById('modalTitle').innerText = '<?php echo __('edit_appointment'); ?>';
document.getElementById('apt_id').value = info.event.id; document.getElementById('apt_id').value = info.event.id;
$('#apt_patient_id').val(props.patient_id).trigger('change'); $('#apt_patient_id').val(props.patient_id).trigger('change');

View File

@ -17,11 +17,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($action === 'create') { if ($action === 'create') {
$stmt = $db->prepare("INSERT INTO doctor_holidays (doctor_id, start_date, end_date, note) VALUES (?, ?, ?, ?)"); $stmt = $db->prepare("INSERT INTO doctor_holidays (doctor_id, start_date, end_date, note) VALUES (?, ?, ?, ?)");
$stmt->execute([$doctor_id, $start_date, $end_date, $note]); $stmt->execute([$doctor_id, $start_date, $end_date, $note]);
$_SESSION['flash_message'] = "Holiday added successfully."; $_SESSION['flash_message'] = __('holiday_added_successfully');
} else { } else {
$stmt = $db->prepare("UPDATE doctor_holidays SET doctor_id = ?, start_date = ?, end_date = ?, note = ? WHERE id = ?"); $stmt = $db->prepare("UPDATE doctor_holidays SET doctor_id = ?, start_date = ?, end_date = ?, note = ? WHERE id = ?");
$stmt->execute([$doctor_id, $start_date, $end_date, $note, $id]); $stmt->execute([$doctor_id, $start_date, $end_date, $note, $id]);
$_SESSION['flash_message'] = "Holiday updated successfully."; $_SESSION['flash_message'] = __('holiday_updated_successfully');
} }
} }
} elseif ($action === 'delete') { } elseif ($action === 'delete') {
@ -29,7 +29,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($id) { if ($id) {
$stmt = $db->prepare("DELETE FROM doctor_holidays WHERE id = ?"); $stmt = $db->prepare("DELETE FROM doctor_holidays WHERE id = ?");
$stmt->execute([$id]); $stmt->execute([$id]);
$_SESSION['flash_message'] = "Holiday deleted successfully."; $_SESSION['flash_message'] = __('holiday_deleted_successfully');
} }
} }
// Redirect to avoid resubmission // Redirect to avoid resubmission
@ -70,7 +70,7 @@ $holidays = $db->query("SELECT dh.*, d.name_$lang as doctor_name FROM doctor_hol
<tr> <tr>
<td colspan="5" class="text-center py-4 text-muted"> <td colspan="5" class="text-center py-4 text-muted">
<i class="bi bi-calendar-x display-6 d-block mb-2"></i> <i class="bi bi-calendar-x display-6 d-block mb-2"></i>
No holidays found. <?php echo __('no_holidays_found'); ?>
</td> </td>
</tr> </tr>
<?php else: ?> <?php else: ?>
@ -111,7 +111,7 @@ $holidays = $db->query("SELECT dh.*, d.name_$lang as doctor_name FROM doctor_hol
<div class="mb-3"> <div class="mb-3">
<label class="form-label small text-muted"><?php echo __('doctor'); ?></label> <label class="form-label small text-muted"><?php echo __('doctor'); ?></label>
<select name="doctor_id" id="doctorId" class="form-select" required> <select name="doctor_id" id="doctorId" class="form-select" required>
<option value="">Select Doctor</option> <option value=""><?php echo __('select') . ' ' . __('doctor'); ?></option>
<?php foreach ($doctors as $d): ?> <?php foreach ($doctors as $d): ?>
<option value="<?php echo $d['id']; ?>"><?php echo htmlspecialchars($d['name']); ?></option> <option value="<?php echo $d['id']; ?>"><?php echo htmlspecialchars($d['name']); ?></option>
<?php endforeach; ?> <?php endforeach; ?>
@ -171,7 +171,7 @@ function showEditModal(data) {
} }
function deleteHoliday(id) { function deleteHoliday(id) {
if (confirm('Are you sure you want to delete this holiday?')) { if (confirm('<?php echo __('are_you_sure_delete_holiday'); ?>')) {
document.getElementById('deleteId').value = id; document.getElementById('deleteId').value = id;
document.getElementById('deleteForm').submit(); document.getElementById('deleteForm').submit();
} }

View File

@ -52,9 +52,9 @@ $appointments = $stmt->fetchAll();
<label class="form-label small text-muted"><?php echo __('status'); ?></label> <label class="form-label small text-muted"><?php echo __('status'); ?></label>
<select name="status" class="form-select" onchange="this.form.submit()"> <select name="status" class="form-select" onchange="this.form.submit()">
<option value=""><?php echo __('all'); ?></option> <option value=""><?php echo __('all'); ?></option>
<option value="Scheduled" <?php echo $search_status === 'Scheduled' ? 'selected' : ''; ?>>Scheduled</option> <option value="Scheduled" <?php echo $search_status === 'Scheduled' ? 'selected' : ''; ?>><?php echo __('scheduled'); ?></option>
<option value="Completed" <?php echo $search_status === 'Completed' ? 'selected' : ''; ?>>Completed</option> <option value="Completed" <?php echo $search_status === 'Completed' ? 'selected' : ''; ?>><?php echo __('completed'); ?></option>
<option value="Cancelled" <?php echo $search_status === 'Cancelled' ? 'selected' : ''; ?>>Cancelled</option> <option value="Cancelled" <?php echo $search_status === 'Cancelled' ? 'selected' : ''; ?>><?php echo __('cancelled'); ?></option>
</select> </select>
</div> </div>
</form> </form>
@ -74,7 +74,7 @@ $appointments = $stmt->fetchAll();
<div class="card-body"> <div class="card-body">
<div class="d-flex justify-content-between align-items-start mb-3"> <div class="d-flex justify-content-between align-items-start mb-3">
<span class="badge <?php echo $app['status'] === 'Completed' ? 'bg-success' : ($app['status'] === 'Cancelled' ? 'bg-danger' : 'bg-primary'); ?>"> <span class="badge <?php echo $app['status'] === 'Completed' ? 'bg-success' : ($app['status'] === 'Cancelled' ? 'bg-danger' : 'bg-primary'); ?>">
<?php echo $app['status']; ?> <?php echo __(strtolower($app['status'])); ?>
</span> </span>
<small class="text-muted fw-bold"> <small class="text-muted fw-bold">
<?php echo date('H:i', strtotime($app['start_time'])); ?> <?php echo date('H:i', strtotime($app['start_time'])); ?>
@ -88,7 +88,7 @@ $appointments = $stmt->fetchAll();
<div class="mb-3 p-2 bg-light rounded small"> <div class="mb-3 p-2 bg-light rounded small">
<i class="bi bi-geo-alt text-danger me-1"></i> <i class="bi bi-geo-alt text-danger me-1"></i>
<?php echo nl2br(htmlspecialchars($app['address'] ?? 'No address provided')); ?> <?php echo nl2br(htmlspecialchars($app['address'] ?? __('no_address_provided'))); ?>
</div> </div>
<div class="d-flex align-items-center mb-3"> <div class="d-flex align-items-center mb-3">
@ -104,7 +104,7 @@ $appointments = $stmt->fetchAll();
} elseif ($app['nurse_id']) { } elseif ($app['nurse_id']) {
echo htmlspecialchars($app['nurse_name']) . ' (' . __('nurse') . ')'; echo htmlspecialchars($app['nurse_name']) . ' (' . __('nurse') . ')';
} else { } else {
echo '<span class="text-danger">Unassigned</span>'; echo '<span class="text-danger">' . __('unassigned') . '</span>';
} }
?> ?>
</span> </span>
@ -113,7 +113,7 @@ $appointments = $stmt->fetchAll();
<?php if ($app['reason']): ?> <?php if ($app['reason']): ?>
<p class="small text-muted mb-0"> <p class="small text-muted mb-0">
<strong>Reason:</strong> <?php echo htmlspecialchars($app['reason']); ?> <strong><?php echo __('reason_label'); ?>:</strong> <?php echo htmlspecialchars($app['reason']); ?>
</p> </p>
<?php endif; ?> <?php endif; ?>
</div> </div>
@ -121,7 +121,7 @@ $appointments = $stmt->fetchAll();
<!-- Actions --> <!-- Actions -->
<?php if ($app['status'] === 'Scheduled'): ?> <?php if ($app['status'] === 'Scheduled'): ?>
<button class="btn btn-sm btn-outline-success" onclick="completeHomeVisit(<?php echo $app['id']; ?>, <?php echo $app['patient_id']; ?>, <?php echo $app['doctor_id'] ?: 'null'; ?>, <?php echo $app['nurse_id'] ?: 'null'; ?>)"> <button class="btn btn-sm btn-outline-success" onclick="completeHomeVisit(<?php echo $app['id']; ?>, <?php echo $app['patient_id']; ?>, <?php echo $app['doctor_id'] ?: 'null'; ?>, <?php echo $app['nurse_id'] ?: 'null'; ?>)">
<i class="bi bi-check2-circle"></i> Complete <i class="bi bi-check2-circle"></i> <?php echo __('complete'); ?>
</button> </button>
<?php endif; ?> <?php endif; ?>
</div> </div>
@ -136,7 +136,7 @@ $appointments = $stmt->fetchAll();
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">Complete Home Visit</h5> <h5 class="modal-title"><?php echo __('complete_home_visit'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -147,21 +147,21 @@ $appointments = $stmt->fetchAll();
<input type="hidden" id="chv_nurse_id" name="nurse_id"> <input type="hidden" id="chv_nurse_id" name="nurse_id">
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Notes / Treatment</label> <label class="form-label"><?php echo __('notes_treatment'); ?></label>
<textarea class="form-control" id="chv_treatment_plan" name="treatment_plan" rows="3"></textarea> <textarea class="form-control" id="chv_treatment_plan" name="treatment_plan" rows="3"></textarea>
</div> </div>
<div class="form-check mb-3"> <div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="chv_create_bill" checked> <input class="form-check-input" type="checkbox" id="chv_create_bill" checked>
<label class="form-check-label" for="chv_create_bill"> <label class="form-check-label" for="chv_create_bill">
Create Bill? <?php echo __('create_bill'); ?>?
</label> </label>
</div> </div>
</form> </form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('close'); ?></button>
<button type="button" class="btn btn-primary" onclick="submitHomeVisitCompletion()">Save & Complete</button> <button type="button" class="btn btn-primary" onclick="submitHomeVisitCompletion()"><?php echo __('save_complete'); ?></button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,94 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800"><?php echo __('user_profile'); ?></h1>
</div>
<?php if (isset($errors) && !empty($errors)): ?>
<div class="alert alert-danger">
<ul>
<?php foreach ($errors as $error): ?>
<li><?php echo htmlspecialchars($error); ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php if (isset($success_msg)): ?>
<div class="alert alert-success">
<?php echo htmlspecialchars($success_msg); ?>
</div>
<?php endif; ?>
<div class="row">
<div class="col-md-4">
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary"><?php echo __('profile_picture'); ?></h6>
</div>
<div class="card-body text-center">
<img src="<?php echo !empty($user['avatar']) ? $user['avatar'] : 'assets/images/default-avatar.png'; ?>"
class="img-profile rounded-circle mb-3"
style="width: 150px; height: 150px; object-fit: cover;"
alt="Profile Picture">
<p class="text-muted mb-1"><?php echo htmlspecialchars($user['name']); ?></p>
<p class="text-muted small"><?php echo htmlspecialchars($user['email']); ?></p>
<p class="badge badge-primary"><?php echo htmlspecialchars($user['role_slug']); ?></p>
</div>
</div>
</div>
<div class="col-md-8">
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary"><?php echo __('edit_profile'); ?></h6>
</div>
<div class="card-body">
<form method="POST" enctype="multipart/form-data">
<div class="form-group">
<label for="name"><?php echo __('name'); ?></label>
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($user['name']); ?>" required>
</div>
<div class="form-group">
<label for="email"><?php echo __('email'); ?></label>
<input type="email" class="form-control" id="email" name="email" value="<?php echo htmlspecialchars($user['email']); ?>" required>
</div>
<div class="form-group">
<label for="avatar"><?php echo __('change_avatar'); ?></label>
<div class="custom-file">
<input type="file" class="custom-file-input" id="avatar" name="avatar" accept="image/*">
<label class="custom-file-label" for="avatar"><?php echo __('choose_file'); ?></label>
</div>
<small class="form-text text-muted"><?php echo __('allowed_file_types'); ?>: jpg, jpeg, png, gif</small>
</div>
<hr>
<h6 class="mb-3 font-weight-bold text-gray-800"><?php echo __('change_password'); ?> <small class="text-muted font-weight-normal">(<?php echo __('leave_blank_to_keep_current'); ?>)</small></h6>
<div class="form-row">
<div class="form-group col-md-6">
<label for="password"><?php echo __('new_password'); ?></label>
<input type="password" class="form-control" id="password" name="password" minlength="6">
</div>
<div class="form-group col-md-6">
<label for="password_confirm"><?php echo __('confirm_password'); ?></label>
<input type="password" class="form-control" id="password_confirm" name="password_confirm" minlength="6">
</div>
</div>
<button type="submit" class="btn btn-primary btn-block"><?php echo __('save_changes'); ?></button>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
// Show file name in custom file input
$(".custom-file-input").on("change", function() {
var fileName = $(this).val().split("\\").pop();
$(this).next(".custom-file-label").addClass("selected").html(fileName);
});
</script>

View File

@ -118,7 +118,11 @@ $available_permissions = [
</td> </td>
<td> <td>
<?php if ($role['slug'] !== 'admin'): ?> <?php if ($role['slug'] !== 'admin'): ?>
<button class="btn btn-sm btn-outline-primary" onclick='editPermissions(<?php echo json_encode($role); ?>)'> <button class="btn btn-sm btn-outline-primary"
data-id="<?php echo $role['id']; ?>"
data-name="<?php echo htmlspecialchars($role['name']); ?>"
data-permissions='<?php echo htmlspecialchars($role['permissions'], ENT_QUOTES, 'UTF-8'); ?>'
onclick="editPermissions(this)">
<i class="bi bi-shield-lock"></i> <?php echo __('permissions'); ?> <i class="bi bi-shield-lock"></i> <?php echo __('permissions'); ?>
</button> </button>
<?php else: ?> <?php else: ?>
@ -218,9 +222,9 @@ $available_permissions = [
</div> </div>
<script> <script>
function editPermissions(role) { function editPermissions(btn) {
document.getElementById('permRoleId').value = role.id; document.getElementById('permRoleId').value = btn.dataset.id;
document.getElementById('permRoleName').innerText = role.name; document.getElementById('permRoleName').innerText = btn.dataset.name;
// Reset all checkboxes // Reset all checkboxes
document.querySelectorAll('.perm-check').forEach(c => c.checked = false); document.querySelectorAll('.perm-check').forEach(c => c.checked = false);
@ -228,7 +232,7 @@ function editPermissions(role) {
// Check active permissions // Check active permissions
let perms = []; let perms = [];
try { try {
perms = JSON.parse(role.permissions); perms = JSON.parse(btn.dataset.permissions);
} catch(e) { } catch(e) {
perms = []; perms = [];
} }
@ -254,4 +258,4 @@ document.getElementById('selectAllAdd').addEventListener('change', function() {
let checked = this.checked; let checked = this.checked;
document.querySelectorAll('.perm-check-add').forEach(c => c.checked = checked); document.querySelectorAll('.perm-check-add').forEach(c => c.checked = checked);
}); });
</script> </script>

View File

@ -102,7 +102,13 @@ $roles = $stmt->fetchAll(PDO::FETCH_ASSOC);
</td> </td>
<td><?php echo date('Y-m-d', strtotime($user['created_at'])); ?></td> <td><?php echo date('Y-m-d', strtotime($user['created_at'])); ?></td>
<td> <td>
<button class="btn btn-sm btn-outline-primary me-1" onclick="editUser(<?php echo htmlspecialchars(json_encode($user)); ?>)"> <button class="btn btn-sm btn-outline-primary me-1"
data-id="<?php echo $user['id']; ?>"
data-name="<?php echo htmlspecialchars($user['name']); ?>"
data-email="<?php echo htmlspecialchars($user['email']); ?>"
data-role="<?php echo $user['role_id']; ?>"
data-active="<?php echo $user['active']; ?>"
onclick="editUser(this)">
<i class="bi bi-pencil"></i> <i class="bi bi-pencil"></i>
</button> </button>
<?php if ($user['id'] != $_SESSION['user_id']): ?> <?php if ($user['id'] != $_SESSION['user_id']): ?>
@ -229,12 +235,12 @@ $roles = $stmt->fetchAll(PDO::FETCH_ASSOC);
</div> </div>
<script> <script>
function editUser(user) { function editUser(btn) {
document.getElementById('editUserId').value = user.id; document.getElementById('editUserId').value = btn.dataset.id;
document.getElementById('editUserName').value = user.name; document.getElementById('editUserName').value = btn.dataset.name;
document.getElementById('editUserEmail').value = user.email; document.getElementById('editUserEmail').value = btn.dataset.email;
document.getElementById('editUserRole').value = user.role_id; document.getElementById('editUserRole').value = btn.dataset.role;
document.getElementById('editUserActive').checked = user.active == 1; document.getElementById('editUserActive').checked = btn.dataset.active == 1;
new bootstrap.Modal(document.getElementById('editUserModal')).show(); new bootstrap.Modal(document.getElementById('editUserModal')).show();
} }
@ -243,4 +249,4 @@ function deleteUser(id) {
document.getElementById('deleteUserId').value = id; document.getElementById('deleteUserId').value = id;
new bootstrap.Modal(document.getElementById('deleteUserModal')).show(); new bootstrap.Modal(document.getElementById('deleteUserModal')).show();
} }
</script> </script>

176
lang.php
View File

@ -193,8 +193,6 @@ $translations = [
'filter' => 'Filter', 'filter' => 'Filter',
'all_departments' => 'All Departments', 'all_departments' => 'All Departments',
'total' => 'Total', 'total' => 'Total',
// Dashboard & Common Missing Keys
'total_patients' => 'Total Patients', 'total_patients' => 'Total Patients',
'today_appointments' => 'Today\'s Appointments', 'today_appointments' => 'Today\'s Appointments',
'today' => 'Today', 'today' => 'Today',
@ -218,16 +216,97 @@ $translations = [
'reason' => 'Reason', 'reason' => 'Reason',
'new_visit' => 'New Visit', 'new_visit' => 'New Visit',
'select' => 'Select', 'select' => 'Select',
'select_doctor' => 'Select Doctor',
'issue_token' => 'Issue Token', 'issue_token' => 'Issue Token',
'select_service' => 'Select Service', 'select_service' => 'Select Service',
'print_bill' => 'Print Bill', 'print_bill' => 'Print Bill',
'close' => 'Close', 'close' => 'Close',
'print' => 'Print',
// Login & Auth 'add_bill' => 'Add Bill',
'patient_number' => 'File No.',
'age' => 'Age',
'policy_number' => 'Policy No.',
'or' => 'or',
'showing' => 'Showing',
'of' => 'of',
'add_holiday' => 'Add Holiday',
'edit_holiday' => 'Edit Holiday',
'start_date' => 'Start Date',
'end_date' => 'End Date',
'note' => 'Note',
'delete_holiday' => 'Delete Holiday',
'are_you_sure_delete_holiday' => 'Are you sure you want to delete this holiday?',
'holiday_added_successfully' => 'Holiday added successfully.',
'holiday_updated_successfully' => 'Holiday updated successfully.',
'holiday_deleted_successfully' => 'Holiday deleted successfully.',
'no_holidays_found' => 'No holidays found',
'add_service' => 'Add Service',
'edit_service' => 'Edit Service',
'delete_service' => 'Delete Service',
'service_added_successfully' => 'Service added successfully',
'service_updated_successfully' => 'Service updated successfully',
'service_deleted_successfully' => 'Service deleted successfully',
'no_services_found' => 'No services found',
'are_you_sure_delete_service' => 'Are you sure you want to delete this service?',
'price' => 'Price',
'search_by_name' => 'Search by name',
'save_changes' => 'Save Changes',
'add_city' => 'Add City',
'edit_city' => 'Edit City',
'delete_city' => 'Delete City',
'no_cities_found' => 'No cities found',
'are_you_sure_delete' => 'Are you sure you want to delete?',
'action_cannot_be_undone' => 'This action cannot be undone.',
'add_ad' => 'Add Ad',
'edit_ad' => 'Edit Ad',
'delete_ad' => 'Delete Ad',
'ad_text_en' => 'Ad Text (English)',
'ad_text_ar' => 'Ad Text (Arabic)',
'no_ads_found' => 'No ads found',
'scheduled' => 'Scheduled',
'completed' => 'Completed',
'cancelled' => 'Cancelled',
'no_address_provided' => 'No address provided',
'provider' => 'Provider',
'unassigned' => 'Unassigned',
'reason_label' => 'Reason',
'complete' => 'Complete',
'complete_home_visit' => 'Complete Home Visit',
'notes_treatment' => 'Notes / Treatment',
'create_bill' => 'Create Bill',
'save_complete' => 'Save & Complete',
'no_appointments_found' => 'No appointments found',
'doctor_is_on_holiday_on_this_date' => 'Selected doctor is on holiday on this date.',
'edit_appointment' => 'Edit Appointment',
'appointment_details' => 'Appointment Details',
'print_daily_list' => 'Print Daily List',
'appointments_list' => 'Appointments List',
'back' => 'Back',
'no_appointments' => 'No appointments found',
'printed_on' => 'Printed on',
'fill_all_fields' => 'Please fill in all fields', 'fill_all_fields' => 'Please fill in all fields',
'invalid_credentials' => 'Invalid email or password', 'invalid_credentials' => 'Invalid email or password',
'login_to_continue' => 'Login to continue to your account', 'login_to_continue' => 'Login to continue to your account',
'forgot_password' => 'Forgot Password?', 'forgot_password' => 'Forgot Password?',
'user_profile' => 'User Profile',
'profile_picture' => 'Profile Picture',
'edit_profile' => 'Edit Profile',
'change_avatar' => 'Change Avatar',
'choose_file' => 'Choose file',
'allowed_file_types' => 'Allowed file types',
'change_password' => 'Change Password',
'leave_blank_to_keep_current' => 'Leave blank to keep current password',
'new_password' => 'New Password',
'confirm_password' => 'Confirm Password',
'name_required' => 'Name is required',
'email_required' => 'Email is required',
'email_already_taken' => 'Email is already taken',
'password_min_length' => 'Password must be at least 6 characters',
'passwords_do_not_match' => 'Passwords do not match',
'invalid_file_type' => 'Invalid file type. Only JPG, PNG and GIF are allowed.',
'upload_failed' => 'File upload failed',
'profile_updated_successfully' => 'Profile updated successfully',
'error_updating_profile' => 'Error updating profile',
], ],
'ar' => [ 'ar' => [
'dashboard' => 'لوحة التحكم', 'dashboard' => 'لوحة التحكم',
@ -422,8 +501,6 @@ $translations = [
'filter' => 'تصفية', 'filter' => 'تصفية',
'all_departments' => 'كل الأقسام', 'all_departments' => 'كل الأقسام',
'total' => 'الإجمالي', 'total' => 'الإجمالي',
// Dashboard & Common Missing Keys - Arabic
'total_patients' => 'إجمالي المرضى', 'total_patients' => 'إجمالي المرضى',
'today_appointments' => 'مواعيد اليوم', 'today_appointments' => 'مواعيد اليوم',
'today' => 'اليوم', 'today' => 'اليوم',
@ -447,15 +524,96 @@ $translations = [
'reason' => 'السبب', 'reason' => 'السبب',
'new_visit' => 'زيارة جديدة', 'new_visit' => 'زيارة جديدة',
'select' => 'اختر', 'select' => 'اختر',
'select_doctor' => 'اختر الطبيب',
'issue_token' => 'إصدار تذكرة', 'issue_token' => 'إصدار تذكرة',
'select_service' => 'اختر الخدمة', 'select_service' => 'اختر الخدمة',
'print_bill' => 'طباعة الفاتورة', 'print_bill' => 'طباعة الفاتورة',
'close' => 'إغلاق', 'close' => 'إغلاق',
'print' => 'طباعة',
// Login & Auth 'add_bill' => 'إضافة فاتورة',
'patient_number' => 'رقم الملف',
'age' => 'العمر',
'policy_number' => 'رقم البوليصة',
'or' => 'أو',
'showing' => 'عرض',
'of' => 'من',
'add_holiday' => 'إضافة إجازة',
'edit_holiday' => 'تعديل إجازة',
'start_date' => 'تاريخ البدء',
'end_date' => 'تاريخ الانتهاء',
'note' => 'ملاحظة',
'delete_holiday' => 'حذف إجازة',
'are_you_sure_delete_holiday' => 'هل أنت متأكد من حذف هذه الإجازة؟',
'holiday_added_successfully' => 'تم إضافة الإجازة بنجاح.',
'holiday_updated_successfully' => 'تم تحديث الإجازة بنجاح.',
'holiday_deleted_successfully' => 'تم حذف الإجازة بنجاح.',
'no_holidays_found' => 'لم يتم العثور على إجازات',
'add_service' => 'إضافة خدمة',
'edit_service' => 'تعديل خدمة',
'delete_service' => 'حذف خدمة',
'service_added_successfully' => 'تم إضافة الخدمة بنجاح',
'service_updated_successfully' => 'تم تحديث الخدمة بنجاح',
'service_deleted_successfully' => 'تم حذف الخدمة بنجاح',
'no_services_found' => 'لم يتم العثور على خدمات',
'are_you_sure_delete_service' => 'هل أنت متأكد من حذف هذه الخدمة؟',
'price' => 'السعر',
'search_by_name' => 'بحث بالاسم',
'save_changes' => 'حفظ التغييرات',
'add_city' => 'إضافة مدينة',
'edit_city' => 'تعديل مدينة',
'delete_city' => 'حذف مدينة',
'no_cities_found' => 'لم يتم العثور على مدن',
'are_you_sure_delete' => 'هل أنت متأكد من الحذف؟',
'action_cannot_be_undone' => 'لا يمكن التراجع عن هذا الإجراء.',
'add_ad' => 'إضافة إعلان',
'edit_ad' => 'تعديل إعلان',
'delete_ad' => 'حذف إعلان',
'ad_text_en' => 'نص الإعلان (إنجليزي)',
'ad_text_ar' => 'نص الإعلان (عربي)',
'no_ads_found' => 'لا توجد إعلانات',
'scheduled' => 'مجدولة',
'completed' => 'مكتملة',
'cancelled' => 'ملغاة',
'no_address_provided' => 'لم يتم تقديم عنوان',
'provider' => 'المقدم',
'unassigned' => 'غير معين',
'reason_label' => 'السبب',
'complete' => 'إكمال',
'complete_home_visit' => 'إكمال الزيارة المنزلية',
'notes_treatment' => 'ملاحظات / العلاج',
'create_bill' => 'إنشاء فاتورة',
'save_complete' => 'حفظ وإكمال',
'no_appointments_found' => 'لا توجد مواعيد',
'doctor_is_on_holiday_on_this_date' => 'الطبيب المحدد في إجازة في هذا التاريخ.',
'edit_appointment' => 'تعديل موعد',
'appointment_details' => 'تفاصيل الموعد',
'print_daily_list' => 'طباعة القائمة اليومية',
'appointments_list' => 'قائمة المواعيد',
'back' => 'رجوع',
'no_appointments' => 'لم يتم العثور على مواعيد',
'printed_on' => 'تم الطباعة في',
'fill_all_fields' => 'يرجى ملء جميع الحقول', 'fill_all_fields' => 'يرجى ملء جميع الحقول',
'invalid_credentials' => 'البريد الإلكتروني أو كلمة المرور غير صحيحة', 'invalid_credentials' => 'البريد الإلكتروني أو كلمة المرور غير صحيحة',
'login_to_continue' => 'قم بتسجيل الدخول للمتابعة', 'login_to_continue' => 'قم بتسجيل الدخول للمتابعة',
'forgot_password' => 'هل نسيت كلمة المرور؟', 'forgot_password' => 'هل نسيت كلمة المرور؟',
'user_profile' => 'الملف الشخصي',
'profile_picture' => 'الصورة الشخصية',
'edit_profile' => 'تعديل الملف الشخصي',
'change_avatar' => 'تغيير الصورة',
'choose_file' => 'اختر ملف',
'allowed_file_types' => 'أنواع الملفات المسموحة',
'change_password' => 'تغيير كلمة المرور',
'leave_blank_to_keep_current' => 'اتركه فارغاً للاحتفاظ بكلمة المرور الحالية',
'new_password' => 'كلمة المرور الجديدة',
'confirm_password' => 'تأكيد كلمة المرور',
'name_required' => 'الاسم مطلوب',
'email_required' => 'البريد الإلكتروني مطلوب',
'email_already_taken' => 'البريد الإلكتروني مسجل مسبقاً',
'password_min_length' => 'يجب أن تتكون كلمة المرور من 6 أحرف على الأقل',
'passwords_do_not_match' => 'كلمات المرور غير متطابقة',
'invalid_file_type' => 'نوع الملف غير صالح. مسموح فقط بـ JPG, PNG, GIF.',
'upload_failed' => 'فشل تحميل الملف',
'profile_updated_successfully' => 'تم تحديث الملف الشخصي بنجاح',
'error_updating_profile' => 'خطأ في تحديث الملف الشخصي',
] ]
]; ];

99
profile.php Normal file
View File

@ -0,0 +1,99 @@
<?php
require_once 'includes/auth.php';
require_once 'helpers.php';
check_auth();
$user = current_user();
$page_title = __('user_profile');
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
$password_confirm = $_POST['password_confirm'] ?? '';
$errors = [];
if (empty($name)) {
$errors[] = __('name_required');
}
if (empty($email)) {
$errors[] = __('email_required');
}
// Check if email is taken by another user
$stmt = $db->prepare("SELECT id FROM users WHERE email = ? AND id != ?");
$stmt->execute([$email, $user['id']]);
if ($stmt->fetch()) {
$errors[] = __('email_already_taken');
}
if (!empty($password)) {
if (strlen($password) < 6) {
$errors[] = __('password_min_length');
}
if ($password !== $password_confirm) {
$errors[] = __('passwords_do_not_match');
}
}
// Handle avatar upload
$avatar_path = $user['avatar'];
if (isset($_FILES['avatar']) && $_FILES['avatar']['error'] === UPLOAD_ERR_OK) {
$file_tmp = $_FILES['avatar']['tmp_name'];
$file_name = $_FILES['avatar']['name'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
$allowed_exts = ['jpg', 'jpeg', 'png', 'gif'];
if (!in_array($file_ext, $allowed_exts)) {
$errors[] = __('invalid_file_type');
} else {
$upload_dir = 'assets/uploads/users/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
$new_file_name = 'user_' . $user['id'] . '_' . time() . '.' . $file_ext;
$destination = $upload_dir . $new_file_name;
if (move_uploaded_file($file_tmp, $destination)) {
$avatar_path = $destination;
} else {
$errors[] = __('upload_failed');
}
}
}
if (empty($errors)) {
try {
$sql = "UPDATE users SET name = ?, email = ?, avatar = ?";
$params = [$name, $email, $avatar_path];
if (!empty($password)) {
$sql .= ", password = ?";
$params[] = password_hash($password, PASSWORD_DEFAULT);
}
$sql .= " WHERE id = ?";
$params[] = $user['id'];
$stmt = $db->prepare($sql);
$stmt->execute($params);
// Update session cache
unset($_SESSION['user_cache']);
$user = current_user(); // Refresh user data
$success_msg = __('profile_updated_successfully');
} catch (Exception $e) {
$errors[] = __('error_updating_profile') . ': ' . $e->getMessage();
}
}
}
require_once 'includes/layout/header.php';
require_once 'includes/pages/profile.php';
require_once 'includes/layout/footer.php';

View File

@ -1,5 +0,0 @@
<?php
$_SERVER['REQUEST_METHOD'] = 'GET';
$_GET['start'] = '2026-03-15';
$_GET['end'] = '2026-03-22';
require_once 'api/appointments.php';

View File

@ -1,28 +0,0 @@
<?php
$data = [
'action' => 'create',
'patient_id' => 2,
'doctor_id' => 1,
'nurse_id' => null,
'visit_type' => 'Clinic',
'address' => '',
'start_time' => '2026-03-25T10:00',
'reason' => 'Test API'
];
$ch = curl_init('http://localhost/api/appointments.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($response === false) {
echo "Curl Error: " . curl_error($ch);
} else {
echo "HTTP Code: $http_code\n";
echo "Response: $response\n";
}
curl_close($ch);