Files
server/src/main/resources/static/js/dashboard.js

231 lines
7.4 KiB
JavaScript

function buildIdentity(admin) {
const identity = document.createElement("div");
identity.className = "identity-row";
const avatar = document.createElement(admin.avatarUrl ? "img" : "div");
avatar.className = "avatar";
if (admin.avatarUrl) {
avatar.src = admin.avatarUrl;
avatar.alt = `${admin.displayName || admin.login} avatar`;
} else {
avatar.classList.add("avatar-fallback");
avatar.textContent = (admin.displayName || admin.login || "?").charAt(0).toUpperCase();
}
const details = document.createElement("div");
details.className = "identity-text";
const title = document.createElement("p");
title.className = "list-title";
title.textContent = admin.displayName || admin.login;
const subtitle = document.createElement("p");
subtitle.className = "muted";
subtitle.textContent = `@${admin.login}`;
details.appendChild(title);
details.appendChild(subtitle);
identity.appendChild(avatar);
identity.appendChild(details);
return identity;
}
function renderAdmins(list) {
const adminList = document.getElementById("admin-list");
if (!adminList) return;
adminList.innerHTML = "";
if (!list || list.length === 0) {
const empty = document.createElement("li");
empty.textContent = "No channel admins yet";
adminList.appendChild(empty);
return;
}
list.forEach((admin) => {
const li = document.createElement("li");
li.className = "stacked-list-item";
li.appendChild(buildIdentity(admin));
const actions = document.createElement("div");
actions.className = "actions";
const removeBtn = document.createElement("button");
removeBtn.type = "button";
removeBtn.className = "secondary";
removeBtn.textContent = "Remove";
removeBtn.addEventListener("click", () => removeAdmin(admin.login));
actions.appendChild(removeBtn);
li.appendChild(actions);
adminList.appendChild(li);
});
}
function renderSuggestedAdmins(list) {
const suggestionList = document.getElementById("admin-suggestions");
if (!suggestionList) return;
suggestionList.innerHTML = "";
if (!list || list.length === 0) {
const empty = document.createElement("li");
empty.className = "stacked-list-item";
empty.textContent = "No moderator suggestions right now";
suggestionList.appendChild(empty);
return;
}
list.forEach((admin) => {
const li = document.createElement("li");
li.className = "stacked-list-item";
li.appendChild(buildIdentity(admin));
const actions = document.createElement("div");
actions.className = "actions";
const addBtn = document.createElement("button");
addBtn.type = "button";
addBtn.className = "ghost";
addBtn.textContent = "Add channel admin";
addBtn.addEventListener("click", () => addAdmin(admin.login));
actions.appendChild(addBtn);
li.appendChild(actions);
suggestionList.appendChild(li);
});
}
function fetchSuggestedAdmins() {
fetch(`/api/channels/${broadcaster}/admins/suggestions`)
.then((r) => {
if (!r.ok) {
throw new Error("Failed to load admin suggestions");
}
return r.json();
})
.then(renderSuggestedAdmins)
.catch(() => {
renderSuggestedAdmins([]);
});
}
function fetchAdmins() {
fetch(`/api/channels/${broadcaster}/admins`)
.then((r) => {
if (!r.ok) {
throw new Error("Failed to load admins");
}
return r.json();
})
.then(renderAdmins)
.catch(() => {
renderAdmins([]);
showToast("Unable to load admins right now. Please try again.", "error");
});
}
function removeAdmin(username) {
if (!username) return;
fetch(`/api/channels/${encodeURIComponent(broadcaster)}/admins/${encodeURIComponent(username)}`, {
method: "DELETE",
})
.then((response) => {
if (!response.ok) {
throw new Error();
}
fetchAdmins();
fetchSuggestedAdmins();
})
.catch(() => {
showToast("Failed to remove admin. Please retry.", "error");
});
}
function addAdmin(usernameFromAction) {
const input = document.getElementById("new-admin");
const username = (usernameFromAction || input?.value || "").trim();
if (!username) {
showToast("Enter a Twitch username to add as an admin.", "info");
return;
}
fetch(`/api/channels/${broadcaster}/admins`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username }),
})
.then((response) => {
if (!response.ok) {
throw new Error("Add admin failed");
}
if (input) {
input.value = "";
}
showToast(`Added @${username} as an admin.`, "success");
fetchAdmins();
fetchSuggestedAdmins();
})
.catch(() => showToast("Unable to add admin right now. Please try again.", "error"));
}
function renderCanvasSettings(settings) {
const widthInput = document.getElementById("canvas-width");
const heightInput = document.getElementById("canvas-height");
if (widthInput) widthInput.value = Math.round(settings.width);
if (heightInput) heightInput.value = Math.round(settings.height);
}
function fetchCanvasSettings() {
fetch(`/api/channels/${broadcaster}/canvas`)
.then((r) => {
if (!r.ok) {
throw new Error("Failed to load canvas settings");
}
return r.json();
})
.then(renderCanvasSettings)
.catch(() => {
renderCanvasSettings({ width: 1920, height: 1080 });
showToast("Using default canvas size. Unable to load saved settings.", "warning");
});
}
function saveCanvasSettings() {
const widthInput = document.getElementById("canvas-width");
const heightInput = document.getElementById("canvas-height");
const status = document.getElementById("canvas-status");
const width = parseFloat(widthInput?.value) || 0;
const height = parseFloat(heightInput?.value) || 0;
if (width <= 0 || height <= 0) {
showToast("Please enter a valid width and height.", "info");
return;
}
if (status) status.textContent = "Saving...";
fetch(`/api/channels/${broadcaster}/canvas`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ width, height }),
})
.then((r) => {
if (!r.ok) {
throw new Error("Failed to save canvas");
}
return r.json();
})
.then((settings) => {
renderCanvasSettings(settings);
if (status) status.textContent = "Saved.";
showToast("Canvas size saved successfully.", "success");
setTimeout(() => {
if (status) status.textContent = "";
}, 2000);
})
.catch(() => {
if (status) status.textContent = "Unable to save right now.";
showToast("Unable to save canvas size. Please retry.", "error");
});
}
fetchAdmins();
fetchSuggestedAdmins();
fetchCanvasSettings();