// 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 ? `
` : '';
// 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 ? `
` : '';
// 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);
}
});
}