ft_transcendence/frontend/src/auth.ts
2026-01-13 17:02:21 +01:00

118 lines
2.7 KiB
TypeScript

import { showError } from "@app/toast";
import client from "@app/api";
import cookie from "js-cookie";
import { ensureWindowState, isNullish } from "@app/utils";
import { handleRoute, navigateTo } from "./routing";
cookie.remove("pkce");
const headerProfile =
document.querySelector<HTMLDivElement>("#header-profile")!;
ensureWindowState();
window.__state.user ??= null;
export type User = {
id: string;
guest: boolean;
name: string;
desc: string;
selfInfo?: {
loginName?: string;
providerId?: string;
providerUser?: string;
};
};
declare module "ft_state" {
interface State {
user: User | null;
_headerProfile: boolean;
_reloadOnAuthChange: boolean;
lastAuthChange: number;
}
}
export function getUser(): Readonly<User> | null {
return window.__state.user;
}
export function isLogged(): boolean {
return window.__state.user !== null;
}
export function setUser(newUser: User | null) {
let sendEvent = window.__state.user?.id !== newUser?.id;
window.__state.user = newUser;
updateHeaderProfile();
if (sendEvent) {
const event = new CustomEvent("ft:userChange", {
detail: isNullish(newUser)
? null
: { id: newUser.id, name: newUser.name },
});
document.dispatchEvent(event);
}
}
export function updateHeaderProfile() {
if (window.__state.user !== null) {
headerProfile.innerText = window.__state.user.name;
} else {
headerProfile.innerText = "Login";
}
}
export async function updateUser(): Promise<Readonly<User> | null> {
try {
let res = await client.getUser({ user: "me" });
if (res.kind === "success") {
setUser(res.payload);
return res.payload;
} else if (res.kind === "failure") {
// well no user :D
setUser(null);
return null;
} else if (res.kind === "notLoggedIn") {
setUser(null);
return null;
} else {
setUser(null);
showError(`unknown response: ${JSON.stringify(res)}`);
return null;
}
} catch (e) {
setUser(null);
showError(`failed to get user: ${e}`);
return null;
}
}
window.__state._headerProfile ??= false;
if (!window.__state._headerProfile) {
headerProfile.addEventListener("click", () => {
if (window.__state.user === null) {
navigateTo(
`/login?returnTo=${encodeURIComponent(window.location.pathname)}`,
);
} else {
navigateTo("/profile");
}
});
window.__state._headerProfile = true;
}
window.__state._reloadOnAuthChange ??= false;
if (!window.__state._reloadOnAuthChange) {
document.addEventListener("ft:userChange", () => {
// if the last forced auth change is less than 1000 sec old -> we do nothing
if (Date.now() - (window.__state.lastAuthChange ?? Date.now()) < 1000)
return;
handleRoute();
});
window.__state._reloadOnAuthChange = true;
}
updateHeaderProfile();
Object.assign(window as any, { getUser, setUser, updateUser, isLogged });