Private
Public Access
1
0

refacto: Keeping entrypoints clean and making files by purpose

This commit is contained in:
gauvainboiche
2026-03-29 13:28:18 +02:00
parent 79cf3ca13e
commit 84af90e81e
13 changed files with 1198 additions and 1167 deletions

147
public/src/auth.js Normal file
View File

@@ -0,0 +1,147 @@
import { apiLogin, apiRegister, apiGetMe } from "./api.js";
import { setCurrentTeam, updateTeamSegmented, 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 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");
updateTeamSegmented();
}
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 ─────────────────────────────────────────────────────────────
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);
});
// ── 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);