Outlook changes
This commit is contained in:
@@ -14,15 +14,22 @@ $isAdmin = (($currentUser['role'] ?? '') === 'ADMIN');
|
||||
$db = get_db_connection();
|
||||
$userBoards = fociz_get_user_boards_with_lanes($db, $userId, $isAdmin);
|
||||
|
||||
// Haal initiële inbox data op (met 45s cache, tenzij ?refresh=1)
|
||||
// Haal alle beschikbare mailmappen op (exclusief SPAM/Junk, Prullenbak/Deleted, Outbox, Drafts)
|
||||
$forceRefresh = !empty($_GET['refresh']) && $_GET['refresh'] === '1';
|
||||
$foldersData = microsoft_fetch_mail_folders($userId, $forceRefresh);
|
||||
$mailFolders = $foldersData['folders'] ?? [];
|
||||
$totalUnreadCount = (int)($foldersData['total_unread'] ?? 0);
|
||||
|
||||
// Haal initiële inbox data op (met 45s cache, tenzij ?refresh=1)
|
||||
$inboxData = microsoft_fetch_inbox_messages($userId, 30, false, $forceRefresh);
|
||||
$messages = $inboxData['messages'] ?? [];
|
||||
$isDemo = !empty($inboxData['is_demo']);
|
||||
$unreadCount = (int)($inboxData['unread_count'] ?? 0);
|
||||
$warning = $inboxData['warning'] ?? '';
|
||||
$isDemo = !empty($inboxData['is_demo']) || !empty($foldersData['is_demo']);
|
||||
$warning = $inboxData['warning'] ?? ($foldersData['warning'] ?? '');
|
||||
$needsReconsent = !empty($inboxData['needs_reconsent']);
|
||||
|
||||
// Bereken actuele ongelezen aantal: neem het hoogste van total_unread over mappen en inbox unread_count
|
||||
$unreadCount = max($totalUnreadCount, (int)($inboxData['unread_count'] ?? 0));
|
||||
|
||||
// Controleer status
|
||||
$stmtInt = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'OUTLOOK' AND is_enabled = 1");
|
||||
$stmtInt->execute([$userId]);
|
||||
@@ -31,6 +38,7 @@ $isOutlookConfigured = !empty($outlookInt['access_token']) && empty($outlookInt[
|
||||
$isLiveMail = $isOutlookConfigured && !$isDemo;
|
||||
|
||||
$jsonMessages = json_encode($messages, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
|
||||
$jsonFolders = json_encode($mailFolders, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
|
||||
?>
|
||||
|
||||
<div class="max-w-7xl mx-auto space-y-6">
|
||||
@@ -143,15 +151,15 @@ $jsonMessages = json_encode($messages, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_Q
|
||||
<!-- Twee-kolommen Mail Interface -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6 min-h-[600px]">
|
||||
|
||||
<!-- Linker kolom: Berichtenlijst (5 kolommen) -->
|
||||
<!-- Linker kolom: Berichtenlijst & Mappen (5 kolommen) -->
|
||||
<div id="mailListColumn" class="lg:col-span-5 fociz-card p-3 sm:p-4 flex flex-col h-[720px] overflow-hidden">
|
||||
<div class="text-xs font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500 px-2 py-1 mb-2 flex items-center justify-between">
|
||||
<span>Inbox Berichten (<span id="visibleMailCount"><?= count($messages) ?></span>)</span>
|
||||
<span>Inbox & Mappen (<span id="visibleMailCount"><?= count($messages) ?></span>)</span>
|
||||
<span class="text-[10px] text-slate-400 font-normal">Sorteer: Nieuwste eerst</span>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-y-auto space-y-1.5 pr-1" id="mailListContainer">
|
||||
<!-- Wordt dynamisch gerenderd via JS -->
|
||||
<div class="flex-1 overflow-y-auto space-y-2.5 pr-1 custom-scrollbar" id="mailFoldersContainer">
|
||||
<!-- Wordt dynamisch gerenderd via JS (Inbox open, overige mappen inklapbaar) -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -527,7 +535,12 @@ $jsonMessages = json_encode($messages, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_Q
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let allMessages = <?= $jsonMessages ?>;
|
||||
let mailFolders = <?= $jsonFolders ?>;
|
||||
let folderMessagesMap = {
|
||||
'inbox': <?= $jsonMessages ?>
|
||||
};
|
||||
let expandedFolders = new Set(['inbox']); // Inbox is standaard geopend, overige mappen ingeklapt
|
||||
let loadingFolders = new Set();
|
||||
let activeFilter = 'all'; // 'all' | 'unread'
|
||||
let selectedMessage = null;
|
||||
|
||||
@@ -537,101 +550,234 @@ function setMailFilter(filter) {
|
||||
const btnUnread = document.getElementById('filterBtn_unread');
|
||||
|
||||
if (filter === 'all') {
|
||||
btnAll.className = "flex-1 sm:flex-none px-3.5 py-1.5 rounded-lg bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-xs transition";
|
||||
btnUnread.className = "flex-1 sm:flex-none px-3.5 py-1.5 rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white transition";
|
||||
btnAll.className = "flex-1 sm:flex-none px-3.5 py-1.5 rounded-lg bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-xs transition cursor-pointer";
|
||||
btnUnread.className = "flex-1 sm:flex-none px-3.5 py-1.5 rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white transition cursor-pointer";
|
||||
} else {
|
||||
btnUnread.className = "flex-1 sm:flex-none px-3.5 py-1.5 rounded-lg bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-xs transition";
|
||||
btnAll.className = "flex-1 sm:flex-none px-3.5 py-1.5 rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white transition";
|
||||
}
|
||||
btnUnread.className = "flex-1 sm:flex-none px-3.5 py-1.5 rounded-lg bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-xs transition cursor-pointer";
|
||||
btnAll.className = "flex-1 sm:flex-none px-3.5 py-1.5 rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white transition cursor-pointer";
|
||||
|
||||
applyMailSearch();
|
||||
}
|
||||
|
||||
function applyMailSearch() {
|
||||
const q = (document.getElementById('mailSearchInput')?.value || '').toLowerCase().trim();
|
||||
let filtered = allMessages;
|
||||
|
||||
if (activeFilter === 'unread') {
|
||||
filtered = filtered.filter(m => !m.is_read);
|
||||
}
|
||||
|
||||
if (q) {
|
||||
filtered = filtered.filter(m => {
|
||||
const sub = (m.subject || '').toLowerCase();
|
||||
const from = (m.from_name || '').toLowerCase() + ' ' + (m.from_email || '').toLowerCase();
|
||||
const prev = (m.body_preview || '').toLowerCase();
|
||||
return sub.includes(q) || from.includes(q) || prev.includes(q);
|
||||
// Bij ongelezen filter: klap automatisch alle mappen met ongelezen mails open!
|
||||
mailFolders.forEach(f => {
|
||||
const msgs = folderMessagesMap[f.id];
|
||||
const hasUnread = msgs ? msgs.some(m => !m.is_read) : ((f.unread_count || 0) > 0);
|
||||
if (hasUnread) {
|
||||
expandedFolders.add(f.id);
|
||||
if (!folderMessagesMap[f.id]) {
|
||||
loadFolderMessagesInBackground(f.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
renderMailList(filtered);
|
||||
renderFolders();
|
||||
}
|
||||
|
||||
function renderMailList(list) {
|
||||
const container = document.getElementById('mailListContainer');
|
||||
const countEl = document.getElementById('visibleMailCount');
|
||||
if (countEl) countEl.innerText = list.length;
|
||||
function applyMailSearch() {
|
||||
renderFolders();
|
||||
}
|
||||
|
||||
if (!list || list.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="text-center py-12 text-slate-400 text-xs">
|
||||
<i data-lucide="inbox" class="w-8 h-8 text-slate-300 dark:text-slate-700 mx-auto mb-2"></i>
|
||||
<p>Geen berichten gevonden.</p>
|
||||
</div>
|
||||
`;
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
async function loadFolderMessagesInBackground(folderId) {
|
||||
if (loadingFolders.has(folderId) || folderMessagesMap[folderId]) return;
|
||||
loadingFolders.add(folderId);
|
||||
renderFolders();
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/mail.php?action=get_folder_messages&folder_id=${encodeURIComponent(folderId)}&limit=30`);
|
||||
const data = await res.json();
|
||||
if (data.success && Array.isArray(data.messages)) {
|
||||
folderMessagesMap[folderId] = data.messages;
|
||||
const fObj = mailFolders.find(f => f.id === folderId);
|
||||
if (fObj && typeof data.unread_count === 'number') {
|
||||
fObj.unread_count = data.unread_count;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Fout bij ophalen berichten voor map ' + folderId, e);
|
||||
} finally {
|
||||
loadingFolders.delete(folderId);
|
||||
updateTotalCounters();
|
||||
renderFolders();
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleFolder(folderId) {
|
||||
if (expandedFolders.has(folderId)) {
|
||||
expandedFolders.delete(folderId);
|
||||
renderFolders();
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
list.forEach(m => {
|
||||
const isSelected = selectedMessage && selectedMessage.id === m.id;
|
||||
const isUnread = !m.is_read;
|
||||
const initials = (m.from_name || 'NL').split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase();
|
||||
expandedFolders.add(folderId);
|
||||
|
||||
let cardClass = isSelected
|
||||
? 'bg-sky-50 dark:bg-sky-950/40 border-sky-400 dark:border-sky-700 shadow-xs'
|
||||
: (isUnread ? 'bg-white dark:bg-[#111624] border-slate-200 dark:border-slate-800 hover:border-slate-300 font-semibold' : 'bg-slate-50/60 dark:bg-[#0c0f17]/60 border-slate-100 dark:border-slate-800/60 text-slate-600 dark:text-slate-400');
|
||||
if (!folderMessagesMap[folderId]) {
|
||||
loadingFolders.add(folderId);
|
||||
renderFolders();
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/mail.php?action=get_folder_messages&folder_id=${encodeURIComponent(folderId)}&limit=30`);
|
||||
const data = await res.json();
|
||||
if (data.success && Array.isArray(data.messages)) {
|
||||
folderMessagesMap[folderId] = data.messages;
|
||||
const fObj = mailFolders.find(f => f.id === folderId);
|
||||
if (fObj && typeof data.unread_count === 'number') {
|
||||
fObj.unread_count = data.unread_count;
|
||||
}
|
||||
} else {
|
||||
folderMessagesMap[folderId] = [];
|
||||
}
|
||||
} catch (e) {
|
||||
folderMessagesMap[folderId] = [];
|
||||
} finally {
|
||||
loadingFolders.delete(folderId);
|
||||
updateTotalCounters();
|
||||
renderFolders();
|
||||
}
|
||||
} else {
|
||||
renderFolders();
|
||||
}
|
||||
}
|
||||
|
||||
function renderFolders() {
|
||||
const container = document.getElementById('mailFoldersContainer');
|
||||
if (!container) return;
|
||||
|
||||
const q = (document.getElementById('mailSearchInput')?.value || '').toLowerCase().trim();
|
||||
let totalVisible = 0;
|
||||
let html = '';
|
||||
|
||||
mailFolders.forEach(folder => {
|
||||
const isInbox = (folder.id === 'inbox' || folder.is_inbox);
|
||||
const isExpanded = expandedFolders.has(folder.id);
|
||||
const isLoading = loadingFolders.has(folder.id);
|
||||
const msgs = folderMessagesMap[folder.id] || [];
|
||||
|
||||
let unreadCount = 0;
|
||||
if (folderMessagesMap[folder.id]) {
|
||||
unreadCount = msgs.filter(m => !m.is_read).length;
|
||||
} else {
|
||||
unreadCount = folder.unread_count || 0;
|
||||
}
|
||||
|
||||
let filteredMsgs = msgs;
|
||||
if (activeFilter === 'unread') {
|
||||
filteredMsgs = filteredMsgs.filter(m => !m.is_read);
|
||||
}
|
||||
if (q) {
|
||||
filteredMsgs = filteredMsgs.filter(m => {
|
||||
const sub = (m.subject || '').toLowerCase();
|
||||
const from = (m.from_name || '').toLowerCase() + ' ' + (m.from_email || '').toLowerCase();
|
||||
const prev = (m.body_preview || '').toLowerCase();
|
||||
return sub.includes(q) || from.includes(q) || prev.includes(q);
|
||||
});
|
||||
}
|
||||
|
||||
if (isExpanded) {
|
||||
totalVisible += filteredMsgs.length;
|
||||
}
|
||||
|
||||
const folderTotal = folder.total_count || msgs.length;
|
||||
|
||||
html += `
|
||||
<div onclick="selectMail('${m.id}')" class="group relative p-3 rounded-2xl border transition cursor-pointer ${cardClass}">
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<div class="flex items-center space-x-2 truncate">
|
||||
<div class="w-6 h-6 rounded-lg ${isUnread ? 'bg-sky-600 text-white' : 'bg-slate-200 dark:bg-slate-800 text-slate-600 dark:text-slate-400'} text-[10px] font-bold flex items-center justify-center flex-shrink-0">
|
||||
${initials}
|
||||
<div class="rounded-2xl border border-slate-200/80 dark:border-slate-800/80 bg-white/70 dark:bg-slate-900/40 overflow-hidden shadow-2xs">
|
||||
<!-- Folder Header Accordion Knop -->
|
||||
<button type="button" onclick="toggleFolder('${folder.id}')" class="w-full flex items-center justify-between p-3 select-none transition cursor-pointer ${isInbox ? 'bg-slate-100/90 dark:bg-slate-800/80' : 'bg-slate-50/80 dark:bg-slate-800/40 hover:bg-slate-100 dark:hover:bg-slate-800/70'}">
|
||||
<div class="flex items-center space-x-2.5 min-w-0">
|
||||
<div class="w-7 h-7 rounded-xl ${isInbox ? 'bg-sky-600 text-white shadow-xs' : 'bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-300'} flex items-center justify-center flex-shrink-0">
|
||||
<i data-lucide="${isInbox ? 'inbox' : 'folder'}" class="w-3.5 h-3.5"></i>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1.5 truncate">
|
||||
<span class="text-xs font-bold text-slate-900 dark:text-white truncate">${escapeHtml(folder.name)}</span>
|
||||
<span class="text-[10px] text-slate-400 font-semibold">(${folderTotal})</span>
|
||||
</div>
|
||||
<span class="text-xs ${isUnread ? 'font-black text-slate-900 dark:text-white' : 'font-medium text-slate-700 dark:text-slate-300'} truncate">
|
||||
${escapeHtml(m.from_name)}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1.5 flex-shrink-0">
|
||||
${isUnread ? '<span class="w-2 h-2 rounded-full bg-sky-500"></span>' : ''}
|
||||
${m.has_attachments ? '<i data-lucide="paperclip" class="w-3 h-3 text-slate-400"></i>' : ''}
|
||||
<span class="text-[10px] text-slate-400 font-medium">${escapeHtml(m.received_human || '')}</span>
|
||||
<div class="flex items-center space-x-2 flex-shrink-0 ml-2">
|
||||
${unreadCount > 0 ? `<span class="px-2 py-0.5 rounded-full text-[10px] font-black bg-sky-100 dark:bg-sky-950/70 text-sky-700 dark:text-sky-300 ring-1 ring-sky-500/30">${unreadCount} ongelezen</span>` : ''}
|
||||
<i data-lucide="chevron-down" class="w-4 h-4 text-slate-400 transition-transform duration-200 ${isExpanded ? 'rotate-180' : ''}"></i>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div class="mt-1 text-xs ${isUnread ? 'font-bold text-slate-900 dark:text-white' : 'text-slate-800 dark:text-slate-200'} truncate">
|
||||
${escapeHtml(m.subject)}
|
||||
</div>
|
||||
|
||||
<div class="mt-0.5 text-[11px] text-slate-400 dark:text-slate-500 line-clamp-1 leading-snug">
|
||||
${escapeHtml(m.body_preview || '')}
|
||||
<!-- Folder Berichten Inhoud -->
|
||||
<div class="${isExpanded ? '' : 'hidden'} p-2 space-y-1.5 bg-slate-50/40 dark:bg-[#0c0f17]/30 border-t border-slate-100 dark:border-slate-800/80">
|
||||
${isLoading ? `
|
||||
<div class="p-4 text-center text-xs text-slate-400 flex items-center justify-center space-x-1.5">
|
||||
<i data-lucide="loader-2" class="w-4 h-4 animate-spin text-sky-500"></i>
|
||||
<span>Berichten ophalen uit Outlook...</span>
|
||||
</div>
|
||||
` : (filteredMsgs.length === 0 ? `
|
||||
<div class="py-4 text-center text-slate-400 text-xs italic">
|
||||
${activeFilter === 'unread' ? 'Geen ongelezen berichten in deze map.' : 'Geen berichten gevonden.'}
|
||||
</div>
|
||||
` : filteredMsgs.map(m => renderMessageCardHtml(m)).join(''))}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
container.innerHTML = html;
|
||||
|
||||
const countEl = document.getElementById('visibleMailCount');
|
||||
if (countEl) countEl.innerText = totalVisible;
|
||||
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}
|
||||
|
||||
function renderMessageCardHtml(m) {
|
||||
const isSelected = selectedMessage && selectedMessage.id === m.id;
|
||||
const isUnread = !m.is_read;
|
||||
const initials = (m.from_name || 'NL').split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase();
|
||||
|
||||
let cardClass = isSelected
|
||||
? 'bg-sky-50 dark:bg-sky-950/40 border-sky-400 dark:border-sky-700 shadow-xs'
|
||||
: (isUnread ? 'bg-white dark:bg-[#111624] border-slate-200 dark:border-slate-800 hover:border-slate-300 font-semibold' : 'bg-slate-50/60 dark:bg-[#0c0f17]/60 border-slate-100 dark:border-slate-800/60 text-slate-600 dark:text-slate-400');
|
||||
|
||||
return `
|
||||
<div onclick="selectMail('${m.id}')" class="group relative p-3 rounded-2xl border transition cursor-pointer ${cardClass}">
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<div class="flex items-center space-x-2 truncate">
|
||||
<div class="w-6 h-6 rounded-lg ${isUnread ? 'bg-sky-600 text-white' : 'bg-slate-200 dark:bg-slate-800 text-slate-600 dark:text-slate-400'} text-[10px] font-bold flex items-center justify-center flex-shrink-0">
|
||||
${initials}
|
||||
</div>
|
||||
<span class="text-xs ${isUnread ? 'font-black text-slate-900 dark:text-white' : 'font-medium text-slate-700 dark:text-slate-300'} truncate">
|
||||
${escapeHtml(m.from_name)}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1.5 flex-shrink-0">
|
||||
${isUnread ? '<span class="w-2 h-2 rounded-full bg-sky-500"></span>' : ''}
|
||||
${m.has_attachments ? '<i data-lucide="paperclip" class="w-3 h-3 text-slate-400"></i>' : ''}
|
||||
<span class="text-[10px] text-slate-400 font-medium">${escapeHtml(m.received_human || '')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-1 text-xs ${isUnread ? 'font-bold text-slate-900 dark:text-white' : 'text-slate-800 dark:text-slate-200'} truncate">
|
||||
${escapeHtml(m.subject)}
|
||||
</div>
|
||||
|
||||
<div class="mt-0.5 text-[11px] text-slate-400 dark:text-slate-500 line-clamp-1 leading-snug">
|
||||
${escapeHtml(m.body_preview || '')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderMailList() {
|
||||
renderFolders();
|
||||
}
|
||||
|
||||
async function selectMail(id) {
|
||||
const found = allMessages.find(m => m.id === id);
|
||||
let found = null;
|
||||
let foundFolderId = null;
|
||||
for (const fId in folderMessagesMap) {
|
||||
const m = (folderMessagesMap[fId] || []).find(x => x.id === id);
|
||||
if (m) {
|
||||
found = m;
|
||||
foundFolderId = fId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) return;
|
||||
|
||||
selectedMessage = found;
|
||||
renderMailList(allMessages); // Update actieve styling
|
||||
renderFolders(); // Update actieve styling
|
||||
|
||||
// Toon detail container
|
||||
document.getElementById('noMailSelectedState').classList.add('hidden');
|
||||
@@ -659,9 +805,13 @@ async function selectMail(id) {
|
||||
const data = await res.json();
|
||||
if (data.success && data.message) {
|
||||
renderMailBodyContent(bodyEl, data.message.body_html, data.message.body_text || found.body_preview);
|
||||
found.is_read = true;
|
||||
updateUnreadCount();
|
||||
renderMailList(allMessages);
|
||||
if (!found.is_read) {
|
||||
found.is_read = true;
|
||||
const fObj = mailFolders.find(f => f.id === foundFolderId);
|
||||
if (fObj && fObj.unread_count > 0) fObj.unread_count--;
|
||||
updateTotalCounters();
|
||||
renderFolders();
|
||||
}
|
||||
} else {
|
||||
bodyEl.innerHTML = `<div class="p-4 rounded-xl bg-red-50 text-red-700 text-xs">${data.error || 'Kon bericht niet inladen.'}</div>`;
|
||||
}
|
||||
@@ -784,9 +934,29 @@ function renderMailBodyContent(container, htmlContent, plainContent) {
|
||||
}
|
||||
|
||||
function updateUnreadCount() {
|
||||
const unread = allMessages.filter(m => !m.is_read).length;
|
||||
const el = document.getElementById('countUnread');
|
||||
if (el) el.innerText = unread;
|
||||
updateTotalCounters();
|
||||
}
|
||||
|
||||
function updateTotalCounters() {
|
||||
let totalUnread = 0;
|
||||
let totalAll = 0;
|
||||
|
||||
mailFolders.forEach(f => {
|
||||
const msgs = folderMessagesMap[f.id];
|
||||
if (msgs) {
|
||||
totalUnread += msgs.filter(m => !m.is_read).length;
|
||||
totalAll += msgs.length;
|
||||
} else {
|
||||
totalUnread += (f.unread_count || 0);
|
||||
totalAll += (f.total_count || 0);
|
||||
}
|
||||
});
|
||||
|
||||
const elUnread = document.getElementById('countUnread');
|
||||
if (elUnread) elUnread.innerText = totalUnread;
|
||||
|
||||
const elAll = document.getElementById('countAll');
|
||||
if (elAll) elAll.innerText = totalAll;
|
||||
}
|
||||
|
||||
function closeMobileDetail() {
|
||||
@@ -1182,17 +1352,30 @@ async function refreshMailbox() {
|
||||
if (icon) icon.classList.add('animate-spin');
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/mail.php?action=get_inbox&refresh=1');
|
||||
const res = await fetch('/api/mail.php?action=get_folders&refresh=1');
|
||||
const data = await res.json();
|
||||
if (data.success && data.messages) {
|
||||
allMessages = data.messages;
|
||||
applyMailSearch();
|
||||
updateUnreadCount();
|
||||
if (data.success && Array.isArray(data.folders)) {
|
||||
mailFolders = data.folders;
|
||||
}
|
||||
|
||||
const promises = [...expandedFolders].map(async (fId) => {
|
||||
try {
|
||||
const r = await fetch(`/api/mail.php?action=get_folder_messages&folder_id=${encodeURIComponent(fId)}&limit=30&refresh=1`);
|
||||
const d = await r.json();
|
||||
if (d.success && Array.isArray(d.messages)) {
|
||||
folderMessagesMap[fId] = d.messages;
|
||||
const fObj = mailFolders.find(f => f.id === fId);
|
||||
if (fObj && typeof d.unread_count === 'number') fObj.unread_count = d.unread_count;
|
||||
}
|
||||
} catch (e) {}
|
||||
});
|
||||
await Promise.all(promises);
|
||||
} catch(err) {
|
||||
console.warn('Mail refresh error:', err);
|
||||
} finally {
|
||||
if (icon) icon.classList.remove('animate-spin');
|
||||
updateTotalCounters();
|
||||
renderFolders();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1228,9 +1411,11 @@ document.addEventListener('keydown', function(e) {
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
applyMailSearch();
|
||||
if (allMessages && allMessages.length > 0) {
|
||||
selectMail(allMessages[0].id);
|
||||
updateTotalCounters();
|
||||
renderFolders();
|
||||
const inboxMsgs = folderMessagesMap['inbox'] || [];
|
||||
if (inboxMsgs.length > 0) {
|
||||
selectMail(inboxMsgs[0].id);
|
||||
}
|
||||
|
||||
// Luister naar live websocket/polling event voor nieuwe inkomende e-mails
|
||||
|
||||
Reference in New Issue
Block a user