2026-05-12 23:50:49 +00:00
|
|
|
document.addEventListener("DOMContentLoaded", async () => {
|
|
|
|
|
const username = localStorage.getItem('username');
|
|
|
|
|
const userKey = localStorage.getItem('userKey');
|
|
|
|
|
|
|
|
|
|
if (!username || !userKey) {
|
|
|
|
|
window.location.href = '/';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const response = await fetch('/validate', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
body: JSON.stringify({ username, key: userKey })
|
|
|
|
|
});
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
localStorage.clear();
|
|
|
|
|
window.location.href = '/';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('Validation failed:', err);
|
|
|
|
|
localStorage.clear();
|
|
|
|
|
window.location.href = '/';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-23 17:22:06 +00:00
|
|
|
function escapeHtml(text) {
|
|
|
|
|
if (!text) return text;
|
|
|
|
|
return text
|
|
|
|
|
.replace(/&/g, "&")
|
|
|
|
|
.replace(/</g, "<")
|
|
|
|
|
.replace(/>/g, ">")
|
|
|
|
|
.replace(/"/g, """)
|
|
|
|
|
.replace(/'/g, "'");
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
// User header bar
|
2026-05-12 23:50:49 +00:00
|
|
|
const userInfoEl = document.getElementById('user-info');
|
2026-06-23 17:22:06 +00:00
|
|
|
|
|
|
|
|
const logoutBtn = document.createElement('button');
|
|
|
|
|
logoutBtn.textContent = 'Logout';
|
2026-10-06 02:36:54 +00:00
|
|
|
logoutBtn.className = 'logout-btn';
|
2026-06-23 17:22:06 +00:00
|
|
|
logoutBtn.onclick = async () => {
|
2026-10-06 02:36:54 +00:00
|
|
|
if (confirm("Are you sure you want to logout? This releases your username.")) {
|
2026-06-23 17:22:06 +00:00
|
|
|
try {
|
|
|
|
|
await fetch('/logout', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
body: JSON.stringify({ username, key: userKey })
|
|
|
|
|
});
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error("Logout request failed:", e);
|
|
|
|
|
}
|
|
|
|
|
localStorage.clear();
|
2026-10-06 02:36:54 +00:00
|
|
|
sessionStorage.clear();
|
2026-06-23 17:22:06 +00:00
|
|
|
window.location.href = '/';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const userSpan = document.createElement('span');
|
|
|
|
|
userSpan.innerHTML = `Logged in as: <strong>${escapeHtml(username)}</strong>`;
|
|
|
|
|
|
|
|
|
|
userInfoEl.append(logoutBtn, userSpan);
|
2026-05-12 23:50:49 +00:00
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
const activeRoomsContainer = document.getElementById('active-rooms-container');
|
|
|
|
|
const statsBadge = document.getElementById('stats-badge');
|
|
|
|
|
|
|
|
|
|
// Modal elements
|
|
|
|
|
const joinModal = document.getElementById('join-modal');
|
|
|
|
|
const joinModalForm = document.getElementById('join-modal-form');
|
|
|
|
|
const modalRoomTitle = document.getElementById('modal-room-title');
|
|
|
|
|
const modalPasswordInput = document.getElementById('modal-room-password');
|
|
|
|
|
const modalCancelBtn = document.getElementById('modal-cancel-btn');
|
|
|
|
|
|
|
|
|
|
let pendingJoinRoom = null;
|
|
|
|
|
let pendingJoinHasWP = false;
|
|
|
|
|
|
|
|
|
|
function openJoinModal(roomName, hasWP) {
|
|
|
|
|
pendingJoinRoom = roomName;
|
|
|
|
|
pendingJoinHasWP = hasWP;
|
|
|
|
|
modalRoomTitle.textContent = `🔒 Join "${roomName}"`;
|
|
|
|
|
modalPasswordInput.value = '';
|
|
|
|
|
joinModal.classList.remove('hidden');
|
|
|
|
|
modalPasswordInput.focus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function closeJoinModal() {
|
|
|
|
|
joinModal.classList.add('hidden');
|
|
|
|
|
pendingJoinRoom = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (modalCancelBtn) {
|
|
|
|
|
modalCancelBtn.addEventListener('click', closeJoinModal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (joinModalForm) {
|
|
|
|
|
joinModalForm.addEventListener('submit', async (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
const password = modalPasswordInput.value.trim();
|
|
|
|
|
if (!password || !pendingJoinRoom) return;
|
|
|
|
|
|
|
|
|
|
const joinBtn = document.getElementById('modal-join-btn');
|
|
|
|
|
if (joinBtn) joinBtn.disabled = true;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch('/rooms/join', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
room: pendingJoinRoom,
|
|
|
|
|
password: password,
|
|
|
|
|
username: username,
|
|
|
|
|
key: userKey
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (joinBtn) joinBtn.disabled = false;
|
|
|
|
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
const err = await res.json().catch(() => ({}));
|
|
|
|
|
alert(err.error || 'Incorrect room password.');
|
|
|
|
|
modalPasswordInput.value = '';
|
|
|
|
|
modalPasswordInput.focus();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Success
|
|
|
|
|
sessionStorage.setItem(`room_password_${pendingJoinRoom}`, password);
|
|
|
|
|
const wpParam = pendingJoinHasWP ? '&watchparty=1' : '';
|
|
|
|
|
window.location.href = `/chat.html?room=${encodeURIComponent(pendingJoinRoom)}${wpParam}`;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (joinBtn) joinBtn.disabled = false;
|
|
|
|
|
console.error('Join error:', err);
|
|
|
|
|
alert('Network error while joining room.');
|
|
|
|
|
}
|
2026-05-12 23:50:49 +00:00
|
|
|
});
|
2026-10-06 02:36:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function loadActiveRooms() {
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch('/rooms');
|
|
|
|
|
if (!res.ok) throw new Error('Failed to fetch rooms');
|
|
|
|
|
|
|
|
|
|
const data = await res.json();
|
|
|
|
|
const rooms = data.active_rooms || [];
|
|
|
|
|
const uniqueUsers = data.unique_users || 0;
|
|
|
|
|
|
|
|
|
|
statsBadge.innerHTML = `🟢 Active Rooms: <strong>${rooms.length}</strong> • 👥 Online Users: <strong>${uniqueUsers}</strong>`;
|
|
|
|
|
|
|
|
|
|
activeRoomsContainer.innerHTML = '';
|
|
|
|
|
|
|
|
|
|
if (rooms.length === 0) {
|
|
|
|
|
activeRoomsContainer.innerHTML = `
|
|
|
|
|
<div class="empty-state">
|
|
|
|
|
No active rooms right now.<br>Create an on-demand room below to start chatting!
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
return;
|
2026-05-12 23:50:49 +00:00
|
|
|
}
|
|
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
rooms.forEach(room => {
|
|
|
|
|
const card = document.createElement('div');
|
|
|
|
|
card.className = 'room-card';
|
2026-05-12 23:50:49 +00:00
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
const left = document.createElement('div');
|
|
|
|
|
left.className = 'room-info-left';
|
2026-05-12 23:50:49 +00:00
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
const titleLink = document.createElement('span');
|
|
|
|
|
titleLink.className = 'room-title-link';
|
|
|
|
|
titleLink.textContent = room.name;
|
2026-05-12 23:50:49 +00:00
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
const badges = document.createElement('div');
|
|
|
|
|
badges.className = 'room-badges';
|
|
|
|
|
badges.innerHTML = `
|
|
|
|
|
<span>👥 ${room.users} user${room.users === 1 ? '' : 's'}</span>
|
|
|
|
|
<span class="badge-encrypted">🔒 Encrypted</span>
|
|
|
|
|
${room.has_watchparty ? '<span class="badge-watchparty">🎬 Watch Party</span>' : ''}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
left.append(titleLink, badges);
|
2026-05-12 23:50:49 +00:00
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
const joinBtn = document.createElement('button');
|
|
|
|
|
joinBtn.textContent = 'Join Room';
|
2026-05-12 23:50:49 +00:00
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
const handleJoin = () => {
|
|
|
|
|
const storedPass = sessionStorage.getItem(`room_password_${room.name}`);
|
|
|
|
|
if (storedPass) {
|
|
|
|
|
const wpParam = room.has_watchparty ? '&watchparty=1' : '';
|
|
|
|
|
window.location.href = `/chat.html?room=${encodeURIComponent(room.name)}${wpParam}`;
|
|
|
|
|
} else {
|
|
|
|
|
openJoinModal(room.name, room.has_watchparty);
|
2026-05-12 23:50:49 +00:00
|
|
|
}
|
2026-10-06 02:36:54 +00:00
|
|
|
};
|
2026-05-12 23:50:49 +00:00
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
titleLink.addEventListener('click', handleJoin);
|
|
|
|
|
joinBtn.addEventListener('click', handleJoin);
|
2026-05-12 23:50:49 +00:00
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
card.append(left, joinBtn);
|
|
|
|
|
activeRoomsContainer.appendChild(card);
|
|
|
|
|
});
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('Failed to load active rooms:', err);
|
|
|
|
|
statsBadge.textContent = 'Failed to load rooms';
|
|
|
|
|
}
|
2026-05-12 23:50:49 +00:00
|
|
|
}
|
|
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
await loadActiveRooms();
|
|
|
|
|
setInterval(loadActiveRooms, 3000); // Poll active rooms every 3 seconds
|
|
|
|
|
|
|
|
|
|
// On-Demand Room Creation Form
|
|
|
|
|
const createRoomForm = document.getElementById('create-room-form');
|
|
|
|
|
if (createRoomForm) {
|
|
|
|
|
createRoomForm.addEventListener('submit', async (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
const roomName = document.getElementById('new-room-name').value.trim();
|
|
|
|
|
const password = document.getElementById('new-room-password').value.trim();
|
|
|
|
|
const isWatchParty = document.getElementById('new-room-watchparty').checked;
|
2026-05-12 23:50:49 +00:00
|
|
|
|
2026-10-06 02:36:54 +00:00
|
|
|
if (!roomName || !password) {
|
|
|
|
|
alert('Please enter both a room name and password.');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const createBtn = document.getElementById('create-room-btn');
|
|
|
|
|
createBtn.disabled = true;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch('/rooms/join', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
room: roomName,
|
|
|
|
|
password: password,
|
|
|
|
|
username: username,
|
|
|
|
|
key: userKey
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
createBtn.disabled = false;
|
|
|
|
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
const err = await res.json().catch(() => ({}));
|
|
|
|
|
alert(err.error || 'Failed to create room.');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Store password in session
|
|
|
|
|
sessionStorage.setItem(`room_password_${roomName}`, password);
|
|
|
|
|
const wpParam = isWatchParty ? '&watchparty=1' : '';
|
|
|
|
|
window.location.href = `/chat.html?room=${encodeURIComponent(roomName)}${wpParam}`;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
createBtn.disabled = false;
|
|
|
|
|
console.error('Room creation error:', err);
|
|
|
|
|
alert('Network error while creating room.');
|
|
|
|
|
}
|
|
|
|
|
});
|
2026-05-12 23:50:49 +00:00
|
|
|
}
|
|
|
|
|
});
|