aboutsummaryrefslogtreecommitdiff
path: root/174bg/manager
diff options
context:
space:
mode:
Diffstat (limited to '174bg/manager')
-rw-r--r--174bg/manager/public/index.html120
1 files changed, 96 insertions, 24 deletions
diff --git a/174bg/manager/public/index.html b/174bg/manager/public/index.html
index 8d86443..6773b09 100644
--- a/174bg/manager/public/index.html
+++ b/174bg/manager/public/index.html
@@ -75,6 +75,8 @@
<button id="login">Login with Discord</button>
</section>
+ <p id="oauth-status" style="font-size: 0.9rem"></p>
+
<section
id="authed"
style="display: none; flex-direction: column; gap: 1em"
@@ -207,20 +209,24 @@
}
}
- // ---------------------------------------------------------------------------
- // Role preferences
- // ---------------------------------------------------------------------------
- const ROLES = [
- { value: "ship_captain", text: "Ship Captain" },
- { value: "medical_officer", text: "Medical Officer" },
- { value: "rifleman", text: "Rifleman" },
- { value: "engineer", text: "Engineer" },
- ];
+ // Role options are fetched from the collection schema after auth
+ let ROLES = [];
+
+ async function fetchRoles() {
+ ROLES = [
+ { value: "Ship Captain", text: "Ship Captain" },
+ { value: "Medical Officer", text: "Medical Officer" },
+ { value: "Engineer", text: "Engineer" },
+ { value: "Rifleman", text: "Rifleman" },
+ { value: "Pilot", text: "Pilot" },
+ ];
+ }
let rolesEditing = false;
let rolesTbody;
let rolesEditBtn;
let rolesCancelBtn;
+ let rolesStatus;
function renderRoles(saved, editMode) {
rolesTbody.querySelectorAll("tr").forEach((tr) => {
@@ -273,18 +279,18 @@
}
table.append(thead, rolesTbody);
- container.append(heading, table);
+ rolesStatus = document.createElement("p");
+ rolesStatus.style.cssText = "margin:0; font-size:0.85rem";
+ container.append(heading, table, rolesStatus);
}
function loadRoles() {
rolesEditing = false;
rolesEditBtn.textContent = "✏️ Edit";
rolesCancelBtn.hidden = true;
- renderRoles(pb.authStore.record?.rolePreferences?.roles ?? [], false);
+ renderRoles(pb.authStore.record?.RolePreferencesSelect ?? [], false);
}
- buildRolesSection();
-
const loginBtn = document.getElementById("login");
const logoutBtn = document.getElementById("logout");
const anonymousSection = document.getElementById("anonymous");
@@ -305,8 +311,65 @@
}
}
+ // Complete OAuth redirect if returning from Discord
+ const oauthParams = new URLSearchParams(window.location.search);
+ const storedProvider = localStorage.getItem("pb_oauth_provider");
+ const oauthStatus = document.getElementById("oauth-status");
+
+ if (oauthParams.has("code") && oauthParams.has("state")) {
+ if (!storedProvider) {
+ oauthStatus.textContent =
+ "Login error: OAuth state lost (localStorage empty). Please try again.";
+ oauthStatus.style.color = "red";
+ window.history.replaceState({}, "", window.location.pathname);
+ } else {
+ oauthStatus.textContent = "Completing login...";
+ const provider = JSON.parse(storedProvider);
+ localStorage.removeItem("pb_oauth_provider");
+ const redirectUrl = window.location.origin + window.location.pathname;
+ try {
+ await pb
+ .collection("members")
+ .authWithOAuth2Code(
+ provider.name,
+ oauthParams.get("code"),
+ provider.codeVerifier,
+ redirectUrl,
+ );
+ oauthStatus.style.cssText =
+ "color:green; background:#dfd; border:1px solid #080; border-radius:4px; padding:0.5rem";
+ oauthStatus.textContent = "✅ Login successful!";
+ window.history.replaceState({}, "", window.location.pathname);
+ await fetchRoles();
+ buildRolesSection();
+ updateAuthUI();
+ populateWelcome();
+ populateRequiredInfo();
+ loadRoles();
+ } catch (err) {
+ console.error("OAuth callback failed:", err);
+ const detail = [
+ err?.message,
+ err?.response ? JSON.stringify(err.response) : null,
+ `code=${oauthParams.get("code")?.slice(0, 8)}…`,
+ `state=${oauthParams.get("state")?.slice(0, 8)}…`,
+ `redirect=${redirectUrl}`,
+ `provider=${provider.name}`,
+ ]
+ .filter(Boolean)
+ .join(" | ");
+ oauthStatus.style.cssText =
+ "color:red; background:#fdd; border:1px solid #c00; border-radius:4px; padding:0.5rem; font-family:monospace; font-size:0.8rem; white-space:pre-wrap; word-break:break-all";
+ oauthStatus.textContent = `Login error — send this to your admin:\n${detail}`;
+ window.history.replaceState({}, "", window.location.pathname);
+ }
+ }
+ }
+
updateAuthUI();
if (pb.authStore.isValid) {
+ await fetchRoles();
+ buildRolesSection();
populateWelcome();
populateRequiredInfo();
loadRoles();
@@ -315,14 +378,17 @@
loginBtn.addEventListener("click", async () => {
loginBtn.disabled = true;
try {
- await pb.collection("members").authWithOAuth2({ provider: "discord" });
- updateAuthUI();
- populateWelcome();
- populateRequiredInfo();
- loadRoles();
+ const methods = await pb.collection("members").listAuthMethods();
+ const provider = methods.oauth2.providers.find(
+ (p) => p.name === "discord",
+ );
+ if (!provider) throw new Error("Discord provider not found");
+ const redirectUrl = window.location.origin + window.location.pathname;
+ localStorage.setItem("pb_oauth_provider", JSON.stringify(provider));
+ window.location.href =
+ provider.authUrl + encodeURIComponent(redirectUrl);
} catch (err) {
console.error("Login failed:", err);
- } finally {
loginBtn.disabled = false;
}
});
@@ -337,7 +403,7 @@
rolesEditing = true;
rolesEditBtn.textContent = "💾 Save";
rolesCancelBtn.hidden = false;
- renderRoles(pb.authStore.record?.rolePreferences?.roles ?? [], true);
+ renderRoles(pb.authStore.record?.RolePreferencesSelect ?? [], true);
} else {
const selected = [
...rolesTbody.querySelectorAll("input[type=checkbox]:checked"),
@@ -345,17 +411,23 @@
rolesEditBtn.disabled = true;
rolesCancelBtn.disabled = true;
try {
- const prefs = { roles: selected };
+ const prefs = selected;
await pb
.collection("members")
- .update(pb.authStore.record.id, { rolePreferences: prefs });
- pb.authStore.record.rolePreferences = prefs;
+ .update(pb.authStore.record.id, { RolePreferencesSelect: prefs });
+ pb.authStore.record.RolePreferencesSelect = prefs;
rolesEditing = false;
rolesEditBtn.textContent = "✏️ Edit";
rolesCancelBtn.hidden = true;
+ rolesStatus.textContent = "";
renderRoles(selected, false);
} catch (err) {
console.error("Failed to save role preferences:", err);
+ const msg = err?.response
+ ? JSON.stringify(err.response)
+ : (err?.message ?? String(err));
+ rolesStatus.style.color = "red";
+ rolesStatus.textContent = `Save failed: ${msg}`;
} finally {
rolesEditBtn.disabled = false;
rolesCancelBtn.disabled = false;
@@ -367,7 +439,7 @@
rolesEditing = false;
rolesEditBtn.textContent = "✏️ Edit";
rolesCancelBtn.hidden = true;
- renderRoles(pb.authStore.record?.rolePreferences?.roles ?? [], false);
+ renderRoles(pb.authStore.record?.RolePreferencesSelect ?? [], false);
});
</script>
</html>