/** 401: pidApiRequest já redireciona pro login e devolve null (sem lançar). * Qualquer outro erro (servidor fora, 500) lança: aqui avisa o usuário, senão * a página ficava sem menu e sem explicação nenhuma. Roda uma única vez por * página (pidGetMe cacheia a promise), então o aviso não se repete. */ async function pidRequireAuth() { try { return await pidApiRequest("/me/"); } catch (e) { if (typeof pidAlert === "function") { pidAlert("Não foi possível carregar seus dados. Recarregue a página; se persistir, contate a Inovação.", { titulo: "Não foi possível carregar", }); } return null; } } async function pidLogout() { try { await pidApiRequest("/auth/logout/", { method: "POST" }); } catch (e) { // mesmo se a chamada falhar, força a saída no cliente } window.location.href = "index.html"; } function pidBindPasswordToggle(toggleBtn, input) { if (!toggleBtn || !input) return; toggleBtn.addEventListener("click", () => { const isPassword = input.type === "password"; input.type = isPassword ? "text" : "password"; toggleBtn.setAttribute("aria-label", isPassword ? "Ocultar senha" : "Mostrar senha"); }); } document.addEventListener("DOMContentLoaded", async () => { const form = document.getElementById("login-form"); if (!form) return; try { const me = await pidApiRequest("/me/", { redirectOn401: false }); if (me) { window.location.href = "portal.html"; return; } } catch (e) { // sem sessão ativa — permanece no login } const userInput = document.getElementById("login-user"); const passInput = document.getElementById("login-pass"); const errorEl = document.getElementById("login-error"); const toggleBtn = document.getElementById("toggle-password"); const submitBtn = form.querySelector('button[type="submit"]'); pidBindPasswordToggle(toggleBtn, passInput); form.addEventListener("submit", async (event) => { event.preventDefault(); const username = userInput.value.trim(); // Senha sem trim: a troca de senha grava espaços do começo/fim, e com // trim aqui essa senha deixava de funcionar no login. const password = passInput.value; if (!username || !password) { errorEl.textContent = "Informe login e senha para continuar."; return; } errorEl.textContent = ""; if (submitBtn) submitBtn.disabled = true; try { await pidApiRequest("/auth/login/", { method: "POST", redirectOn401: false, body: { username, password }, }); const tocaIntro = typeof pidIsHalloweenActive === "function" && pidIsHalloweenActive() && typeof pidPlayLoginIntroHalloween === "function" ? pidPlayLoginIntroHalloween : typeof pidIsAniversarioActive === "function" && pidIsAniversarioActive() && typeof pidPlayLoginIntroAniversario === "function" ? pidPlayLoginIntroAniversario : pidPlayLoginIntro; tocaIntro(() => { // Armazenamento bloqueado não pode impedir a navegação: só perde a revelação animada. try { sessionStorage.setItem("pid_reveal_portal", "1"); } catch (e) { // segue sem a animação de revelação } window.location.href = "portal.html"; }); } catch (e) { errorEl.textContent = e.message || "Login ou senha inválidos."; if (submitBtn) submitBtn.disabled = false; } }); });