Refactor code structure for improved readability and maintainability

This commit is contained in:
2026-09-10 11:27:31 +02:00
parent a7aad57e0b
commit 130a43eabc
42 changed files with 2545 additions and 122 deletions
+193 -4
View File
@@ -185,6 +185,86 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$messageType = 'success';
}
}
// 8. Standaard avatar kiezen uit bibliotheek
elseif ($action === 'select_preset_avatar') {
$preset = trim($_POST['avatar_preset'] ?? '');
if (preg_match('/^\/assets\/avatars\/avatar-(0[1-9]|1[0-9]|2[0-4])\.svg$/', $preset)) {
$stmtUp = $db->prepare("UPDATE users SET avatar_url = ? WHERE id = ?");
$stmtUp->execute([$preset, $userId]);
$_SESSION['user_avatar_url'] = $preset;
$user['avatar_url'] = $preset;
$message = "Uw avatar is succesvol bijgewerkt!";
$messageType = 'success';
} else {
$message = "Ongeldige avatar geselecteerd.";
$messageType = 'error';
}
}
// 9. Eigen profielfoto uploaden
elseif ($action === 'upload_custom_avatar') {
if (!isset($_FILES['avatar_file']) || $_FILES['avatar_file']['error'] !== UPLOAD_ERR_OK) {
$message = "Selecteer een geldige afbeelding om te uploaden.";
$messageType = 'error';
} else {
$file = $_FILES['avatar_file'];
$maxSize = 4 * 1024 * 1024; // 4MB
if ($file['size'] > $maxSize) {
$message = "De afbeelding is te groot (maximaal 4MB toegestaan).";
$messageType = 'error';
} else {
$allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mime, $allowedTypes)) {
$message = "Alleen JPG, PNG, WebP of GIF afbeeldingen zijn toegestaan.";
$messageType = 'error';
} else {
$ext = match($mime) {
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/webp' => 'webp',
'image/gif' => 'gif',
default => 'jpg'
};
$uploadDir = __DIR__ . '/assets/uploads/avatars';
if (!is_dir($uploadDir)) {
@mkdir($uploadDir, 0755, true);
}
$filename = "avatar_{$userId}_" . time() . "_" . bin2hex(random_bytes(4)) . ".{$ext}";
$targetPath = $uploadDir . '/' . $filename;
if (move_uploaded_file($file['tmp_name'], $targetPath)) {
$webPath = "/assets/uploads/avatars/{$filename}";
$stmtUp = $db->prepare("UPDATE users SET avatar_url = ? WHERE id = ?");
$stmtUp->execute([$webPath, $userId]);
$_SESSION['user_avatar_url'] = $webPath;
$user['avatar_url'] = $webPath;
$message = "Uw profielfoto is succesvol geüpload en ingesteld!";
$messageType = 'success';
} else {
$message = "Er is een fout opgetreden bij het verplaatsen van het geüploade bestand.";
$messageType = 'error';
}
}
}
}
}
// 10. Avatar verwijderen
elseif ($action === 'remove_avatar') {
$stmtUp = $db->prepare("UPDATE users SET avatar_url = NULL WHERE id = ?");
$stmtUp->execute([$userId]);
unset($_SESSION['user_avatar_url']);
$user['avatar_url'] = null;
$message = "Uw avatar is teruggezet naar de standaard weergave met uw initialen.";
$messageType = 'success';
}
}
// Actuele gegevens ophalen
@@ -228,10 +308,14 @@ require_once __DIR__ . '/includes/header.php';
<div class="relative z-10 flex flex-col sm:flex-row sm:items-center justify-between gap-6">
<div class="flex items-center space-x-4 sm:space-x-5">
<div class="w-16 h-16 sm:w-20 sm:h-20 rounded-2xl bg-gradient-to-tr from-indigo-600 to-sky-500 p-0.5 shadow-sm flex-shrink-0">
<div class="w-full h-full rounded-2xl bg-white dark:bg-[#0c0f17] flex items-center justify-center font-bold text-2xl sm:text-3xl text-indigo-600 dark:text-indigo-400 uppercase">
<?= strtoupper(substr($userProfile['name'], 0, 1)) ?>
</div>
<div class="w-16 h-16 sm:w-20 sm:h-20 rounded-2xl bg-gradient-to-tr from-indigo-600 to-sky-500 p-0.5 shadow-sm flex-shrink-0 overflow-hidden">
<?php if (!empty($userProfile['avatar_url'])): ?>
<img src="<?= htmlspecialchars($userProfile['avatar_url']) ?>" alt="Avatar" class="w-full h-full rounded-2xl object-cover bg-white dark:bg-[#0c0f17]">
<?php else: ?>
<div class="w-full h-full rounded-2xl bg-white dark:bg-[#0c0f17] flex items-center justify-center font-bold text-2xl sm:text-3xl text-indigo-600 dark:text-indigo-400 uppercase">
<?= strtoupper(substr($userProfile['name'], 0, 1)) ?>
</div>
<?php endif; ?>
</div>
<div class="space-y-1">
@@ -419,6 +503,100 @@ require_once __DIR__ . '/includes/header.php';
</div>
</div>
<!-- Sectie 0b: Profielfoto & Avatar Beheer -->
<div class="fociz-card p-6 sm:p-7 space-y-6">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-100 dark:border-slate-800/80">
<div class="flex items-center space-x-3.5">
<div class="w-12 h-12 rounded-2xl bg-gradient-to-tr from-indigo-500 to-pink-500 p-0.5 shadow-xs flex-shrink-0 flex items-center justify-center text-white">
<i data-lucide="smile" class="w-6 h-6"></i>
</div>
<div>
<div class="flex items-center space-x-2">
<h2 class="text-base sm:text-lg font-bold text-slate-900 dark:text-white tracking-tight">Profielfoto & Avatar</h2>
<span class="px-2.5 py-0.5 rounded-full <?= !empty($userProfile['avatar_url']) ? 'bg-teal-50 dark:bg-teal-500/10 border border-teal-200 dark:border-teal-500/20 text-teal-700 dark:text-teal-400' : 'bg-slate-100 dark:bg-slate-800 border border-slate-200 dark:border-slate-700 text-slate-600 dark:text-slate-400' ?> text-[10px] font-semibold">
<?= !empty($userProfile['avatar_url']) ? 'Aangepaste Avatar Actief' : 'Standaard Initiaal-Badge' ?>
</span>
</div>
<p class="text-xs text-slate-500 dark:text-slate-400">Kies een mini-avatar uit de 24 stijlvolle karakters of upload een eigen afbeelding.</p>
</div>
</div>
<?php if (!empty($userProfile['avatar_url'])): ?>
<form method="POST" action="/profile.php" class="self-start sm:self-auto">
<input type="hidden" name="action" value="remove_avatar">
<button type="submit" onclick="return confirm('Avatar herstellen naar standaard initiaal-badge?')" class="inline-flex items-center space-x-1.5 px-3 py-1.5 rounded-xl text-xs font-semibold text-rose-600 dark:text-rose-400 bg-rose-50 dark:bg-rose-950/30 border border-rose-200 dark:border-rose-800/50 hover:bg-rose-100 dark:hover:bg-rose-900/50 transition cursor-pointer">
<i data-lucide="rotate-ccw" class="w-3.5 h-3.5"></i>
<span>Standaard Herstellen</span>
</button>
</form>
<?php endif; ?>
</div>
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
<!-- Linker kolom: 24 Standaard Preset Avatars (8 cols) -->
<div class="lg:col-span-8 space-y-3">
<div class="flex items-center justify-between">
<h3 class="text-xs font-bold text-slate-800 dark:text-slate-200 flex items-center space-x-1.5">
<i data-lucide="sparkles" class="w-3.5 h-3.5 text-indigo-500"></i>
<span>Kies een Karakter (24 Mini Avatars)</span>
</h3>
<span class="text-[11px] text-slate-400 dark:text-slate-500">Klik om direct toe te passen</span>
</div>
<div class="grid grid-cols-4 sm:grid-cols-6 md:grid-cols-8 gap-3 p-4 rounded-2xl bg-slate-50 dark:bg-[#0c0f17] border border-slate-200 dark:border-slate-800">
<?php
for ($i = 1; $i <= 24; $i++):
$numStr = sprintf("%02d", $i);
$avatarPath = "/assets/avatars/avatar-{$numStr}.svg";
$isSelected = ($userProfile['avatar_url'] === $avatarPath);
?>
<form method="POST" action="/profile.php" class="relative group">
<input type="hidden" name="action" value="select_preset_avatar">
<input type="hidden" name="avatar_preset" value="<?= $avatarPath ?>">
<button type="submit" class="w-full aspect-square rounded-2xl p-1 transition transform hover:scale-105 active:scale-95 focus:outline-none cursor-pointer <?= $isSelected ? 'ring-2 ring-indigo-600 dark:ring-indigo-400 bg-indigo-50 dark:bg-indigo-950/40 shadow-sm' : 'hover:bg-white dark:hover:bg-slate-800 border border-transparent' ?>" title="Kies Avatar <?= $numStr ?>">
<img src="<?= $avatarPath ?>" alt="Avatar <?= $numStr ?>" class="w-full h-full rounded-xl object-contain pointer-events-none">
<?php if ($isSelected): ?>
<span class="absolute -top-1 -right-1 w-5 h-5 rounded-full bg-indigo-600 text-white flex items-center justify-center shadow-xs border-2 border-white dark:border-[#0c0f17]">
<i data-lucide="check" class="w-3 h-3 stroke-[3]"></i>
</span>
<?php endif; ?>
</button>
</form>
<?php endfor; ?>
</div>
</div>
<!-- Rechter kolom: Eigen Afbeelding Uploaden (4 cols) -->
<div class="lg:col-span-4 space-y-3">
<h3 class="text-xs font-bold text-slate-800 dark:text-slate-200 flex items-center space-x-1.5">
<i data-lucide="upload-cloud" class="w-3.5 h-3.5 text-sky-500"></i>
<span>Eigen Foto Uploaden</span>
</h3>
<form method="POST" action="/profile.php" enctype="multipart/form-data" class="p-4 rounded-2xl bg-slate-50 dark:bg-[#0c0f17] border border-slate-200 dark:border-slate-800 space-y-4">
<input type="hidden" name="action" value="upload_custom_avatar">
<div class="text-center p-5 border-2 border-dashed border-slate-300 dark:border-slate-700 rounded-xl hover:border-indigo-500 dark:hover:border-indigo-400 transition bg-white dark:bg-[#111622]">
<div class="w-10 h-10 mx-auto mb-2 rounded-xl bg-indigo-50 dark:bg-indigo-950/40 text-indigo-600 dark:text-indigo-400 flex items-center justify-center">
<i data-lucide="image" class="w-5 h-5"></i>
</div>
<label for="customAvatarFile" class="block text-xs font-semibold text-indigo-600 dark:text-indigo-400 hover:underline cursor-pointer mb-1">
Klik om bestand te kiezen
</label>
<p class="text-[10px] text-slate-500 dark:text-slate-400">JPG, PNG, WebP of GIF (max. 4MB)</p>
<input type="file" id="customAvatarFile" name="avatar_file" accept="image/png, image/jpeg, image/webp, image/gif" required class="hidden" onchange="previewUploadAvatar(this)">
<div id="uploadFileName" class="mt-2 text-[11px] font-mono text-slate-700 dark:text-slate-300 truncate hidden"></div>
</div>
<button type="submit" id="uploadAvatarBtn" class="w-full py-2.5 px-4 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold transition shadow-xs flex items-center justify-center space-x-2 cursor-pointer">
<i data-lucide="upload" class="w-4 h-4"></i>
<span>Foto Uploaden &amp; Opslaan</span>
</button>
</form>
</div>
</div>
</div>
<!-- Sectie 1: Mijn Microsoft 365 Outlook Agenda -->
<div class="fociz-card p-6 sm:p-7">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-100 dark:border-slate-800/80">
@@ -911,6 +1089,17 @@ function toggleJiraToken() {
if (window.lucide) lucide.createIcons();
}
function previewUploadAvatar(input) {
if (input.files && input.files[0]) {
const file = input.files[0];
const nameEl = document.getElementById('uploadFileName');
if (nameEl) {
nameEl.textContent = '📄 ' + file.name + ' (' + Math.round(file.size / 1024) + ' KB)';
nameEl.classList.remove('hidden');
}
}
}
// Sync banner status met browser permissie & activeer actuele thema kaart
document.addEventListener('DOMContentLoaded', () => {
// Initialiseer geselecteerde thema-kaart