user profile

This commit is contained in:
Flatlogic Bot 2026-02-23 13:39:33 +00:00
parent 95541b059b
commit 999d73eacf
5 changed files with 271 additions and 10 deletions

View File

@ -20,6 +20,7 @@ $currentUser = function_exists('get_logged_user') ? get_logged_user() : null;
$userName = $currentUser['full_name'] ?? ($currentUser['username'] ?? 'Admin'); $userName = $currentUser['full_name'] ?? ($currentUser['username'] ?? 'Admin');
$userGroup = $currentUser['group_name'] ?? 'System'; $userGroup = $currentUser['group_name'] ?? 'System';
$userInitial = strtoupper(substr($userName, 0, 1)); $userInitial = strtoupper(substr($userName, 0, 1));
$userPic = $currentUser['profile_pic'] ?? null;
$companySettings = function_exists('get_company_settings') ? get_company_settings() : []; $companySettings = function_exists('get_company_settings') ? get_company_settings() : [];
$companyName = $companySettings['company_name'] ?? 'Foody'; $companyName = $companySettings['company_name'] ?? 'Foody';
@ -548,12 +549,17 @@ function can_view($module) {
<!-- User Profile --> <!-- User Profile -->
<div class="dropdown"> <div class="dropdown">
<a href="#" class="d-flex align-items-center text-decoration-none dropdown-toggle" id="userDropdown" data-bs-toggle="dropdown" aria-expanded="false" style="color: var(--text-primary);"> <a href="#" class="d-flex align-items-center text-decoration-none dropdown-toggle" id="userDropdown" data-bs-toggle="dropdown" aria-expanded="false" style="color: var(--text-primary);">
<div class="bg-primary bg-gradient rounded-circle d-flex align-items-center justify-content-center text-white me-2 shadow-sm" style="width:38px;height:38px; font-weight:600;"><?= $userInitial ?></div> <?php if ($userPic): ?>
<img src="../<?= htmlspecialchars($userPic) ?>?v=<?= time() ?>" alt="Profile" class="rounded-circle me-2 shadow-sm" style="width:38px;height:38px; object-fit: cover;">
<?php else: ?>
<div class="bg-primary bg-gradient rounded-circle d-flex align-items-center justify-content-center text-white me-2 shadow-sm" style="width:38px;height:38px; font-weight:600;"><?= $userInitial ?></div>
<?php endif; ?>
<span class="d-none d-sm-inline fw-medium"><?= htmlspecialchars($userName) ?></span> <span class="d-none d-sm-inline fw-medium"><?= htmlspecialchars($userName) ?></span>
</a> </a>
<ul class="dropdown-menu dropdown-menu-end shadow border-0" aria-labelledby="userDropdown"> <ul class="dropdown-menu dropdown-menu-end shadow border-0" aria-labelledby="userDropdown">
<li><span class="dropdown-item-text text-muted small">Signed in as <?= htmlspecialchars($userGroup) ?></span></li> <li><span class="dropdown-item-text text-muted small">Signed in as <?= htmlspecialchars($userGroup) ?></span></li>
<li><hr class="dropdown-divider"></li> <li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="profile.php"><i class="bi bi-person me-2"></i> My Profile</a></li>
<li><a class="dropdown-item" href="company.php"><i class="bi bi-building me-2"></i> Company Settings</a></li> <li><a class="dropdown-item" href="company.php"><i class="bi bi-building me-2"></i> Company Settings</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> Logout</a></li> <li><a class="dropdown-item text-danger" href="/logout.php"><i class="bi bi-box-arrow-right me-2"></i> Logout</a></li>

196
admin/profile.php Normal file
View File

@ -0,0 +1,196 @@
<?php
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../includes/functions.php';
require_login();
$pdo = db();
$currentUser = get_logged_user();
$id = $currentUser['id'];
// Always fetch fresh data from DB
$stmt = $pdo->prepare("SELECT u.*, g.name as group_name, g.permissions
FROM users u
LEFT JOIN user_groups g ON u.group_id = g.id
WHERE u.id = ?");
$stmt->execute([$id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user) {
logout_user();
header('Location: /login.php');
exit;
}
$message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$full_name = $_POST['full_name'];
$email = $_POST['email'];
$pdo->beginTransaction();
try {
$sql = "UPDATE users SET full_name = ?, email = ? WHERE id = ?";
$params = [$full_name, $email, $id];
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
// Update password if provided
if (!empty($_POST['password'])) {
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$pdo->prepare("UPDATE users SET password = ? WHERE id = ?")->execute([$password, $id]);
}
// Handle Profile Picture Upload
if (isset($_FILES['profile_pic']) && $_FILES['profile_pic']['error'] === UPLOAD_ERR_OK) {
$upload_dir = __DIR__ . '/../assets/images/users/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0775, true);
}
$file_tmp = $_FILES['profile_pic']['tmp_name'];
$file_name = $_FILES['profile_pic']['name'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
$allowed_exts = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
if (in_array($file_ext, $allowed_exts)) {
$new_file_name = 'user_' . $id . '_' . uniqid() . '.' . $file_ext;
$upload_path = $upload_dir . $new_file_name;
if (move_uploaded_file($file_tmp, $upload_path)) {
// Delete old profile pic if exists
if ($user['profile_pic'] && file_exists(__DIR__ . '/../' . $user['profile_pic'])) {
unlink(__DIR__ . '/../' . $user['profile_pic']);
}
$profile_pic_path = 'assets/images/users/' . $new_file_name;
$pdo->prepare("UPDATE users SET profile_pic = ? WHERE id = ?")->execute([$profile_pic_path, $id]);
}
}
}
$pdo->commit();
$message = '<div class="alert alert-success">Profile updated successfully!</div>';
// Refresh user data and update session
$stmt->execute([$id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
$_SESSION['user'] = $user;
unset($_SESSION['user']['password']);
} catch (Exception $e) {
$pdo->rollBack();
$message = '<div class="alert alert-danger">Error updating profile: ' . $e->getMessage() . '</div>';
}
}
include 'includes/header.php';
?>
<div class="mb-4">
<h2 class="fw-bold">My Profile</h2>
<p class="text-muted">Manage your personal information and account settings.</p>
</div>
<?= $message ?>
<div class="row">
<div class="col-md-8">
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-body p-4">
<form method="POST" enctype="multipart/form-data">
<div class="row mb-4">
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">FULL NAME</label>
<input type="text" name="full_name" class="form-control" value="<?= htmlspecialchars($user['full_name']) ?>" required>
</div>
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">USERNAME (READ-ONLY)</label>
<input type="text" class="form-control bg-light" value="<?= htmlspecialchars($user['username']) ?>" readonly>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">EMAIL</label>
<input type="email" name="email" class="form-control" value="<?= htmlspecialchars($user['email']) ?>" required>
</div>
<div class="col-md-6">
<label class="form-label small fw-bold text-muted">ROLE / GROUP</label>
<input type="text" class="form-control bg-light" value="<?= htmlspecialchars($user['group_name']) ?>" readonly>
</div>
</div>
<div class="row mb-4">
<div class="col-md-12">
<label class="form-label small fw-bold text-muted">PROFILE PICTURE</label>
<div class="d-flex align-items-center gap-3">
<?php if ($user['profile_pic']): ?>
<img src="../<?= htmlspecialchars($user['profile_pic']) ?>?v=<?= time() ?>" alt="Profile Picture" class="rounded-circle shadow-sm" style="width: 100px; height: 100px; object-fit: cover;">
<?php else: ?>
<div class="bg-primary bg-gradient text-white rounded-circle d-flex align-items-center justify-content-center shadow-sm" style="width: 100px; height: 100px; font-weight: 700; font-size: 2rem;">
<?= strtoupper(substr($user['full_name'] ?: $user['username'], 0, 1)) ?>
</div>
<?php endif; ?>
<div class="flex-grow-1">
<input type="file" name="profile_pic" class="form-control" accept="image/*">
<div class="form-text mt-1">Allowed: JPG, PNG, GIF, WebP. Recommended: Square image.</div>
</div>
</div>
</div>
</div>
<div class="mb-4">
<label class="form-label small fw-bold text-muted">NEW PASSWORD (LEAVE BLANK TO KEEP CURRENT)</label>
<input type="password" name="password" class="form-control" placeholder="******">
</div>
<hr class="my-4">
<div class="d-flex justify-content-end gap-2">
<button type="submit" class="btn btn-primary rounded-pill px-5 fw-bold">Save Changes</button>
</div>
</form>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-0 shadow-sm rounded-4 bg-primary bg-gradient text-white shadow mb-4">
<div class="card-body p-4 text-center">
<div class="mb-3">
<?php if ($user['profile_pic']): ?>
<img src="../<?= htmlspecialchars($user['profile_pic']) ?>?v=<?= time() ?>" alt="Profile Picture" class="rounded-circle shadow-sm border border-3 border-white mx-auto" style="width: 120px; height: 120px; object-fit: cover;">
<?php else: ?>
<div class="bg-white text-primary rounded-circle d-flex align-items-center justify-content-center mx-auto shadow-sm" style="width:120px;height:120px; font-weight:700; font-size:3rem;">
<?= strtoupper(substr($user['full_name'] ?: $user['username'], 0, 1)) ?>
</div>
<?php endif; ?>
</div>
<h4 class="fw-bold mb-1"><?= htmlspecialchars($user['full_name']) ?></h4>
<div class="small opacity-75 mb-3">@<?= htmlspecialchars($user['username']) ?> • <?= htmlspecialchars($user['group_name']) ?></div>
<div class="badge bg-white text-primary rounded-pill px-3 py-2 mb-3">
Active Account
</div>
<div class="small opacity-75">
Member since <?= date('F d, Y', strtotime($user['created_at'])) ?>
</div>
</div>
</div>
<div class="card border-0 shadow-sm rounded-4">
<div class="card-body p-4">
<h6 class="fw-bold mb-3"><i class="bi bi-shield-check me-2 text-primary"></i> Account Security</h6>
<ul class="list-unstyled small mb-0">
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i> Password is encrypted</li>
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i> Role-based access control</li>
<li><i class="bi bi-check-circle-fill text-success me-2"></i> Session-based authentication</li>
</ul>
</div>
</div>
</div>
</div>
<?php include 'includes/footer.php'; ?>

View File

@ -62,6 +62,34 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} }
} }
// Handle Profile Picture Upload
if (isset($_FILES['profile_pic']) && $_FILES['profile_pic']['error'] === UPLOAD_ERR_OK) {
$upload_dir = __DIR__ . '/../assets/images/users/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0775, true);
}
$file_tmp = $_FILES['profile_pic']['tmp_name'];
$file_name = $_FILES['profile_pic']['name'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
$allowed_exts = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
if (in_array($file_ext, $allowed_exts)) {
$new_file_name = 'user_' . $id . '_' . uniqid() . '.' . $file_ext;
$upload_path = $upload_dir . $new_file_name;
if (move_uploaded_file($file_tmp, $upload_path)) {
// Delete old profile pic if exists
if ($user['profile_pic'] && file_exists(__DIR__ . '/../' . $user['profile_pic'])) {
unlink(__DIR__ . '/../' . $user['profile_pic']);
}
$profile_pic_path = 'assets/images/users/' . $new_file_name;
$pdo->prepare("UPDATE users SET profile_pic = ? WHERE id = ?")->execute([$profile_pic_path, $id]);
}
}
}
$pdo->commit(); $pdo->commit();
$message = '<div class="alert alert-success">User updated successfully!</div>'; $message = '<div class="alert alert-success">User updated successfully!</div>';
@ -87,7 +115,9 @@ include 'includes/header.php';
<div class="mb-4"> <div class="mb-4">
<a href="users.php" class="text-decoration-none text-muted small"><i class="bi bi-arrow-left"></i> Back to Users</a> <a href="users.php" class="text-decoration-none text-muted small"><i class="bi bi-arrow-left"></i> Back to Users</a>
<h2 class="fw-bold mt-2">Edit User: <?= htmlspecialchars($user['username']) ?></h2> <div class="d-flex align-items-center mt-2">
<h2 class="fw-bold mb-0">Edit User: <?= htmlspecialchars($user['username']) ?></h2>
</div>
</div> </div>
<?= $message ?> <?= $message ?>
@ -96,7 +126,7 @@ include 'includes/header.php';
<div class="col-md-8"> <div class="col-md-8">
<div class="card border-0 shadow-sm rounded-4 mb-4"> <div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-body p-4"> <div class="card-body p-4">
<form method="POST"> <form method="POST" enctype="multipart/form-data">
<div class="row mb-4"> <div class="row mb-4">
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label small fw-bold text-muted">FULL NAME</label> <label class="form-label small fw-bold text-muted">FULL NAME</label>
@ -123,6 +153,25 @@ include 'includes/header.php';
</div> </div>
</div> </div>
<div class="row mb-4">
<div class="col-md-12">
<label class="form-label small fw-bold text-muted">PROFILE PICTURE</label>
<div class="d-flex align-items-center gap-3">
<?php if ($user['profile_pic']): ?>
<img src="../<?= htmlspecialchars($user['profile_pic']) ?>?v=<?= time() ?>" alt="Profile Picture" class="rounded-circle shadow-sm" style="width: 80px; height: 80px; object-fit: cover;">
<?php else: ?>
<div class="bg-primary bg-gradient text-white rounded-circle d-flex align-items-center justify-content-center shadow-sm" style="width: 80px; height: 80px; font-weight: 700; font-size: 1.5rem;">
<?= strtoupper(substr($user['full_name'] ?: $user['username'], 0, 1)) ?>
</div>
<?php endif; ?>
<div class="flex-grow-1">
<input type="file" name="profile_pic" class="form-control" accept="image/*">
<div class="form-text mt-1">Allowed: JPG, PNG, GIF, WebP. Recommended: Square image.</div>
</div>
</div>
</div>
</div>
<div class="mb-4"> <div class="mb-4">
<label class="form-label small fw-bold text-muted">NEW PASSWORD (LEAVE BLANK TO KEEP CURRENT)</label> <label class="form-label small fw-bold text-muted">NEW PASSWORD (LEAVE BLANK TO KEEP CURRENT)</label>
<input type="password" name="password" class="form-control" placeholder="******"> <input type="password" name="password" class="form-control" placeholder="******">
@ -168,9 +217,13 @@ include 'includes/header.php';
<div class="card-body p-4"> <div class="card-body p-4">
<h5 class="fw-bold mb-3">User Info</h5> <h5 class="fw-bold mb-3">User Info</h5>
<div class="d-flex align-items-center mb-3"> <div class="d-flex align-items-center mb-3">
<div class="bg-white text-primary rounded-circle d-flex align-items-center justify-content-center me-3" style="width:50px;height:50px; font-weight:700; font-size:1.5rem;"> <?php if ($user['profile_pic']): ?>
<?= strtoupper(substr($user['full_name'] ?: $user['username'], 0, 1)) ?> <img src="../<?= htmlspecialchars($user['profile_pic']) ?>?v=<?= time() ?>" alt="Profile Picture" class="rounded-circle shadow-sm border border-2 border-white me-3" style="width: 60px; height: 60px; object-fit: cover;">
</div> <?php else: ?>
<div class="bg-white text-primary rounded-circle d-flex align-items-center justify-content-center me-3" style="width:60px;height:60px; font-weight:700; font-size:1.5rem;">
<?= strtoupper(substr($user['full_name'] ?: $user['username'], 0, 1)) ?>
</div>
<?php endif; ?>
<div> <div>
<div class="fw-bold"><?= htmlspecialchars($user['full_name']) ?></div> <div class="fw-bold"><?= htmlspecialchars($user['full_name']) ?></div>
<div class="small opacity-75">Member since <?= date('M Y', strtotime($user['created_at'])) ?></div> <div class="small opacity-75">Member since <?= date('M Y', strtotime($user['created_at'])) ?></div>

View File

@ -28,7 +28,7 @@ $query = "SELECT u.*, g.name as group_name
if ($search) { if ($search) {
$query .= " WHERE u.username LIKE ? OR u.full_name LIKE ? OR u.email LIKE ?"; $query .= " WHERE u.username LIKE ? OR u.full_name LIKE ? OR u.email LIKE ?";
$params = ["%$search%", "%search%", "%search%"]; $params = ["%$search%", "%$search%", "%$search%"];
} }
$query .= " ORDER BY u.id DESC"; $query .= " ORDER BY u.id DESC";
@ -85,9 +85,13 @@ include 'includes/header.php';
<tr> <tr>
<td class="ps-4"> <td class="ps-4">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<div class="rounded-circle bg-primary bg-opacity-10 text-primary d-flex align-items-center justify-content-center me-3" style="width: 40px; height: 40px; font-weight: 600;"> <?php if ($user['profile_pic']): ?>
<?= strtoupper(substr($user['username'], 0, 1)) ?> <img src="../<?= htmlspecialchars($user['profile_pic']) ?>?v=<?= time() ?>" alt="Profile" class="rounded-circle me-3 shadow-sm border border-2 border-white" style="width: 45px; height: 45px; object-fit: cover;">
</div> <?php else: ?>
<div class="rounded-circle bg-primary bg-opacity-10 text-primary d-flex align-items-center justify-content-center me-3 shadow-sm" style="width: 45px; height: 45px; font-weight: 600;">
<?= strtoupper(substr($user['username'], 0, 1)) ?>
</div>
<?php endif; ?>
<div> <div>
<div class="fw-bold text-dark"><?= htmlspecialchars($user['full_name'] ?: $user['username']) ?></div> <div class="fw-bold text-dark"><?= htmlspecialchars($user['full_name'] ?: $user['username']) ?></div>
<div class="text-muted small">@<?= htmlspecialchars($user['username']) ?></div> <div class="text-muted small">@<?= htmlspecialchars($user['username']) ?></div>

View File

@ -0,0 +1,2 @@
-- Add profile_pic column to users table
ALTER TABLE users ADD COLUMN profile_pic VARCHAR(255) DEFAULT NULL AFTER email;