133 lines
3.9 KiB
JavaScript
133 lines
3.9 KiB
JavaScript
// MusicRoom - Auth module
|
|
// Login, signup, logout, guest authentication
|
|
|
|
(function() {
|
|
const M = window.MusicRoom;
|
|
|
|
// Load current user from session
|
|
M.loadCurrentUser = async function() {
|
|
try {
|
|
const res = await fetch("/api/auth/me");
|
|
const data = await res.json();
|
|
M.currentUser = data.user;
|
|
if (M.currentUser && data.permissions) {
|
|
M.currentUser.permissions = data.permissions;
|
|
}
|
|
M.updateAuthUI();
|
|
} catch (e) {
|
|
M.currentUser = null;
|
|
M.updateAuthUI();
|
|
}
|
|
};
|
|
|
|
// Tab switching
|
|
M.$("#tab-login").onclick = () => {
|
|
M.$("#tab-login").classList.add("active");
|
|
M.$("#tab-signup").classList.remove("active");
|
|
M.$("#login-fields").classList.remove("hidden");
|
|
M.$("#signup-fields").classList.add("hidden");
|
|
M.$("#auth-error").textContent = "";
|
|
M.$("#signup-error").textContent = "";
|
|
};
|
|
|
|
M.$("#tab-signup").onclick = () => {
|
|
M.$("#tab-signup").classList.add("active");
|
|
M.$("#tab-login").classList.remove("active");
|
|
M.$("#signup-fields").classList.remove("hidden");
|
|
M.$("#login-fields").classList.add("hidden");
|
|
M.$("#auth-error").textContent = "";
|
|
M.$("#signup-error").textContent = "";
|
|
};
|
|
|
|
// Login
|
|
M.$("#btn-login").onclick = async () => {
|
|
const username = M.$("#login-username").value.trim();
|
|
const password = M.$("#login-password").value;
|
|
try {
|
|
const res = await fetch("/api/auth/login", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ username, password })
|
|
});
|
|
const data = await res.json();
|
|
if (!res.ok) {
|
|
M.$("#auth-error").textContent = data.error || "Login failed";
|
|
return;
|
|
}
|
|
M.$("#login-username").value = "";
|
|
M.$("#login-password").value = "";
|
|
await M.loadCurrentUser();
|
|
M.loadStreams();
|
|
} catch (e) {
|
|
M.$("#auth-error").textContent = "Login failed";
|
|
}
|
|
};
|
|
|
|
// Signup
|
|
M.$("#btn-signup").onclick = async () => {
|
|
const username = M.$("#signup-username").value.trim();
|
|
const password = M.$("#signup-password").value;
|
|
try {
|
|
const res = await fetch("/api/auth/signup", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ username, password })
|
|
});
|
|
const data = await res.json();
|
|
if (!res.ok) {
|
|
M.$("#signup-error").textContent = data.error || "Signup failed";
|
|
return;
|
|
}
|
|
M.$("#signup-username").value = "";
|
|
M.$("#signup-password").value = "";
|
|
await M.loadCurrentUser();
|
|
M.loadStreams();
|
|
} catch (e) {
|
|
M.$("#signup-error").textContent = "Signup failed";
|
|
}
|
|
};
|
|
|
|
// Guest login
|
|
M.$("#btn-guest").onclick = async () => {
|
|
try {
|
|
const res = await fetch("/api/auth/me");
|
|
const data = await res.json();
|
|
M.currentUser = data.user;
|
|
if (M.currentUser && data.permissions) {
|
|
M.currentUser.permissions = data.permissions;
|
|
}
|
|
M.updateAuthUI();
|
|
if (M.currentUser) M.loadStreams();
|
|
} catch (e) {
|
|
M.$("#auth-error").textContent = "Failed to continue as guest";
|
|
}
|
|
};
|
|
|
|
// Logout
|
|
M.$("#btn-logout").onclick = async () => {
|
|
const wasGuest = M.currentUser?.isGuest;
|
|
await fetch("/api/auth/logout", { method: "POST" });
|
|
M.currentUser = null;
|
|
if (wasGuest) {
|
|
// Guest clicking "Sign In" - show login panel
|
|
M.updateAuthUI();
|
|
} else {
|
|
// Regular user logging out - reload to get new guest session
|
|
M.updateAuthUI();
|
|
}
|
|
};
|
|
|
|
// Kick other clients
|
|
M.$("#btn-kick-others").onclick = async () => {
|
|
try {
|
|
const res = await fetch("/api/auth/kick-others", { method: "POST" });
|
|
const data = await res.json();
|
|
if (res.ok) {
|
|
M.showToast(`Kicked ${data.kicked} other client${data.kicked !== 1 ? 's' : ''}`);
|
|
}
|
|
} catch (e) {
|
|
M.showToast("Failed to kick other clients");
|
|
}
|
|
};
|
|
})();
|