// friends, DM list, and friend request logic async function loadFriends() { try { const res = await fetch(`${API_URL}/friends`, { headers: { 'Authorization': `Bearer ${token}` } }); if (res.ok) { friends = await res.json(); // seed lastSeen for each DM friends.forEach(f => { const key = conversationKey('d', f.id); if (!lastSeen[key]) lastSeen[key] = Date.now(); }); displayFriends(); displayDMList(); // Update Service Worker with friends list for background notifications updateServiceWorkerFriends(); } } catch (error) { console.error('Error loading friends:', error); } } async function loadFriendRequests() { try { const res = await fetch(`${API_URL}/friend-requests`, { headers: { 'Authorization': `Bearer ${token}` } }); if (res.ok) { const requests = await res.json(); displayFriendRequests(requests); } } catch (error) { console.error('Error loading friend requests:', error); } } function displayFriends() { friendsList.innerHTML = ''; if (friends.length === 0) { friendsList.innerHTML = '
No friends yet. Add some!
'; return; } friends.forEach(friend => { const friendEl = document.createElement('div'); friendEl.className = 'friend-item'; let av = friend.avatar_url ? `av` : ''; // Generate badge HTML if user has a system badge let badgeHtml = ''; if (friend.badge) { const badgeClass = friend.badge.toLowerCase().replace(/\s+/g, '-'); badgeHtml = `${friend.badge}`; } friendEl.innerHTML = `${av}@${friend.username}${badgeHtml}`; friendEl.onclick = () => selectDM(friend.id, friend.username); friendsList.appendChild(friendEl); }); } function displayDMList() { dmList.innerHTML = ''; if (friends.length === 0) { dmList.innerHTML = '
No friends
'; return; } friends.forEach(friend => { const userEl = document.createElement('div'); userEl.className = 'dm-user'; userEl.setAttribute('data-user-id', friend.id); let av = friend.avatar_url ? `av` : ''; // Generate badge HTML if user has a system badge let badgeHtml = ''; if (friend.badge) { const badgeClass = friend.badge.toLowerCase().replace(/\s+/g, '-'); badgeHtml = `${friend.badge}`; } userEl.innerHTML = `${av}@${friend.username}${badgeHtml}`; const count = unreadCounts[conversationKey('d', friend.id)]; if (count) { const badge = document.createElement('span'); badge.className = 'unread-badge'; badge.textContent = count; userEl.appendChild(badge); } userEl.onclick = () => selectDM(friend.id, friend.username); dmList.appendChild(userEl); }); } function displayFriendRequests(requests) { friendRequestsList.innerHTML = ''; if (requests.length === 0) { friendRequestsList.innerHTML = '
No pending requests
'; return; } requests.forEach(req => { const reqEl = document.createElement('div'); reqEl.className = 'friend-request-item'; reqEl.innerHTML = ` @${req.username}
`; friendRequestsList.appendChild(reqEl); }); } function displayAddFriendModal() { modalError.textContent = ''; modalError.className = 'modal-error'; friendUsernameInput.value = ''; friendUsernameInput.focus(); } async function sendFriendRequest(username) { if (!username || !username.trim()) { modalError.textContent = 'Please enter a username'; modalError.className = 'modal-error show'; return; } try { const res = await fetch(`${API_URL}/friend-request`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ username: username.trim() }) }); const data = await res.json(); if (res.ok) { modalError.textContent = 'Friend request sent!'; modalError.className = 'modal-error show success'; friendUsernameInput.value = ''; setTimeout(() => { addFriendModal.style.display = 'none'; loadFriendRequests(); }, 1000); } else { modalError.textContent = data.error || 'Error sending request'; modalError.className = 'modal-error show'; } } catch (error) { modalError.textContent = 'Error: ' + error.message; modalError.className = 'modal-error show'; } } async function respondFriendRequest(requestId, action) { try { const res = await fetch(`${API_URL}/friend-request/${requestId}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ action: action }) }); if (res.ok) { loadFriends(); loadFriendRequests(); } } catch (error) { console.error('Error responding to friend request:', error); } } // event hooks for friend UI function initFriendListeners() { addFriendBtn.addEventListener('click', () => { displayAddFriendModal(); addFriendModal.style.display = 'flex'; }); closeModal.addEventListener('click', () => { addFriendModal.style.display = 'none'; }); addFriendModal.addEventListener('click', (e) => { if (e.target === addFriendModal) { addFriendModal.style.display = 'none'; } }); modalAddBtn.addEventListener('click', () => { sendFriendRequest(friendUsernameInput.value); }); friendUsernameInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { e.preventDefault(); sendFriendRequest(friendUsernameInput.value); } }); }