Private
Public Access
1
0
Files
star-wars-wild-space/public/src/auth.js

158 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { apiLogin, apiRegister, apiGetMe, apiFetchPlayerCounts } from "./api.js";
import { setCurrentTeam, refreshFromServer } from "./game.js";
// ── DOM refs ──────────────────────────────────────────────────────────────────
const authOverlay = document.getElementById("authOverlay");
const tabLogin = document.getElementById("tabLogin");
const tabRegister = document.getElementById("tabRegister");
const loginForm = document.getElementById("loginForm");
const registerForm = document.getElementById("registerForm");
const loginUsernameEl = document.getElementById("loginUsername");
const loginPasswordEl = document.getElementById("loginPassword");
const loginErrorEl = document.getElementById("loginError");
const regUsernameEl = document.getElementById("regUsername");
const regEmailEl = document.getElementById("regEmail");
const regPasswordEl = document.getElementById("regPassword");
const registerErrorEl = document.getElementById("registerError");
const regCountBlueEl = document.getElementById("regCountBlue");
const regCountRedEl = document.getElementById("regCountRed");
const userDisplayEl = document.getElementById("userDisplay");
const logoutBtn = document.getElementById("logoutBtn");
// ── Auth state ────────────────────────────────────────────────────────────────
export let authToken = localStorage.getItem("authToken") ?? null;
export let currentUser = null;
// ── Helpers ───────────────────────────────────────────────────────────────────
function showError(el, msg) { el.textContent = msg; el.classList.remove("hidden"); }
function clearError(el) { el.textContent = ""; el.classList.add("hidden"); }
export function showAuthOverlay() { authOverlay.classList.remove("hidden"); }
export function hideAuthOverlay() { authOverlay.classList.add("hidden"); }
// ── Apply user (after login / register / session restore) ─────────────────────
export function applyUser(user, token) {
currentUser = user;
authToken = token;
localStorage.setItem("authToken", token);
setCurrentTeam(user.team);
userDisplayEl.textContent = `${user.username} [${user.team}]`;
logoutBtn.classList.remove("hidden");
}
function logout() {
currentUser = null;
authToken = null;
localStorage.removeItem("authToken");
userDisplayEl.textContent = "—";
logoutBtn.classList.add("hidden");
showAuthOverlay();
}
// ── Session restore ───────────────────────────────────────────────────────────
export async function tryRestoreSession() {
if (!authToken) return false;
try {
const res = await apiGetMe(authToken);
if (!res.ok) { localStorage.removeItem("authToken"); authToken = null; return false; }
const data = await res.json();
applyUser(data.user, data.token);
return true;
} catch {
return false;
}
}
// ── Tab switching ─────────────────────────────────────────────────────────────
async function loadRegisterCounts() {
try {
const counts = await apiFetchPlayerCounts();
const fmt = (n) => `${n} joueur${n > 1 ? "s" : ""}`;
regCountBlueEl.textContent = fmt(counts.blue ?? 0);
regCountRedEl.textContent = fmt(counts.red ?? 0);
} catch { /* silently ignore */ }
}
tabLogin.addEventListener("click", () => {
tabLogin.classList.add("authTab--active");
tabRegister.classList.remove("authTab--active");
loginForm.classList.remove("hidden");
registerForm.classList.add("hidden");
clearError(loginErrorEl);
});
tabRegister.addEventListener("click", () => {
tabRegister.classList.add("authTab--active");
tabLogin.classList.remove("authTab--active");
registerForm.classList.remove("hidden");
loginForm.classList.add("hidden");
clearError(registerErrorEl);
loadRegisterCounts();
});
// ── Login form ────────────────────────────────────────────────────────────────
loginForm.addEventListener("submit", async (e) => {
e.preventDefault();
clearError(loginErrorEl);
const username = loginUsernameEl.value.trim();
const password = loginPasswordEl.value;
if (!username || !password) return;
try {
const res = await apiLogin(username, password);
const data = await res.json();
if (!res.ok) {
const msgs = { invalid_credentials: "Invalid username or password.", missing_fields: "Please fill in all fields." };
showError(loginErrorEl, msgs[data.error] ?? "Login failed.");
return;
}
applyUser(data.user, data.token);
hideAuthOverlay();
await refreshFromServer();
} catch {
showError(loginErrorEl, "Network error. Try again.");
}
});
// ── Register form ─────────────────────────────────────────────────────────────
registerForm.addEventListener("submit", async (e) => {
e.preventDefault();
clearError(registerErrorEl);
const username = regUsernameEl.value.trim();
const email = regEmailEl.value.trim();
const password = regPasswordEl.value;
const teamInput = registerForm.querySelector('input[name="regTeam"]:checked');
if (!teamInput) { showError(registerErrorEl, "Please choose a team."); return; }
try {
const res = await apiRegister(username, email, password, teamInput.value);
const data = await res.json();
if (!res.ok) {
const msgs = {
username_taken: "This username is already taken.",
email_taken: "This email is already registered.",
password_too_short:"Password must be at least 6 characters.",
invalid_username: "Username must be 232 characters.",
missing_fields: "Please fill in all fields.",
invalid_team: "Invalid team selected.",
};
showError(registerErrorEl, msgs[data.error] ?? "Registration failed.");
return;
}
applyUser(data.user, data.token);
hideAuthOverlay();
await refreshFromServer();
} catch {
showError(registerErrorEl, "Network error. Try again.");
}
});
// ── Logout ────────────────────────────────────────────────────────────────────
logoutBtn.addEventListener("click", logout);