Files
2026-07-24 21:42:06 +01:00

143 lines
3.9 KiB
JavaScript

(() => {
let ws = null
let expectingMessage = false
const currentUserEl = document.getElementById('username')
const loginBtn = document.getElementById('login-btn')
const messageLog = document.getElementById('message-log')
const publishForm = document.getElementById('publish-form')
const recipientSelect = document.getElementById('recipient-select')
const messageInput = document.getElementById('message-input')
const onlineList = document.getElementById('online-list')
// Auto-fill username from URL parameter
const urlParams = new URLSearchParams(window.location.search)
const urlUser = urlParams.get('user')
if (urlUser) {
currentUserEl.value = urlUser
}
// Login button handler
loginBtn.addEventListener('click', () => {
const username = currentUserEl.value.trim()
if (!username) {
appendLog('Please enter a username', true)
return
}
// Connect to WebSocket with username
connect(username)
// Show publish form, hide login
loginBtn.style.display = 'none'
currentUserEl.style.display = 'none'
publishForm.style.display = 'flex'
messageInput.disabled = false
messageInput.focus()
appendLog(`Joined as ${username}`)
})
function connect(username) {
const encodedUser = encodeURIComponent(username)
ws = new WebSocket(`ws://${location.host}/ws/subscribe?user=${encodedUser}`)
ws.addEventListener('open', () => {
console.info('WebSocket connected')
refreshUsers()
// Refresh users every 5 seconds
setInterval(refreshUsers, 5000)
})
ws.addEventListener('message', (ev) => {
if (typeof ev.data !== 'string') {
console.error('unexpected message type', typeof ev.data)
return
}
const p = appendLog(ev.data)
if (expectingMessage) {
p.scrollIntoView()
expectingMessage = false
}
})
ws.addEventListener('close', (ev) => {
appendLog(`Disconnected (code: ${ev.code})`, true)
if (ev.code !== 1001) {
appendLog('Reconnecting...', true)
setTimeout(() => connect(username), 2000)
}
})
ws.addEventListener('error', (err) => {
console.error('WebSocket error:', err)
})
}
function refreshUsers() {
fetch('/ws/users')
.then(r => r.json())
.then(users => {
onlineList.textContent = users.join(', ') || 'none'
// Update recipient dropdown
recipientSelect.innerHTML = ''
if (users.length > 0) {
users.forEach(user => {
const opt = document.createElement('option')
opt.value = user
opt.textContent = user
recipientSelect.appendChild(opt)
})
}
})
.catch(err => {
console.error('Failed to refresh users:', err)
})
}
function appendLog(text, error = false) {
const p = document.createElement('p')
const time = new Date().toLocaleTimeString()
p.innerText = `[${time}] ${text}`
if (error) {
p.style.color = '#ff6b6b'
}
messageLog.append(p)
return p
}
// Submit message
publishForm.onsubmit = async (ev) => {
ev.preventDefault()
const recipient = recipientSelect.value.trim()
const msg = messageInput.value.trim()
if (!recipient || !msg) {
appendLog('Please select a recipient and enter a message', true)
return
}
messageInput.value = ''
expectingMessage = true
try {
const payload = JSON.stringify({ to: recipient, message: msg })
const resp = await fetch('/ws/publish', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: payload,
})
if (resp.status !== 202) {
const text = await resp.text()
throw new Error(`Failed: ${text}`)
}
} catch (err) {
appendLog(`Send failed: ${err.message}`, true)
}
}
appendLog('Enter your username to join the chat')
})()