import log from "loglevel"; import { bustItGetCache, itGetCached, itPost } from "@/fetchHelpers"; import { setI18nLanguage } from "@/i18nextWrapper"; import dayjs from "dayjs"; import { defineStore } from "pinia"; let logoutRedirectUrl = import.meta.env.VITE_LOGOUT_REDIRECT || "/"; // TODO: check if user logged in with SSO or login-local if (import.meta.env.VITE_OAUTH_API_BASE_URL) { logoutRedirectUrl = `${ import.meta.env.VITE_OAUTH_API_BASE_URL }logout/?post_logout_redirect_uri=${window.location.origin}`; } // typed state https://stackoverflow.com/questions/71012513/when-using-pinia-and-typescript-how-do-you-use-an-action-to-set-the-state export type AvailableLanguages = "de" | "fr" | "it"; export type UserState = { id: string; first_name: string; last_name: string; email: string; username: string; avatar_url: string; is_superuser: boolean; course_session_experts: number[]; loggedIn: boolean; language: AvailableLanguages; }; let defaultLanguage: AvailableLanguages = "de"; const AVAILABLE_LANGUAGES = ["de", "fr", "it"]; const isAvailableLanguage = (language: string): language is AvailableLanguages => { return AVAILABLE_LANGUAGES.includes(language); }; const languagesWithoutCountryCode = navigator.languages.map( (lang) => lang.split("-")[0] ); for (const language of languagesWithoutCountryCode) { if (isAvailableLanguage(language)) { defaultLanguage = language; break; } } const initialUserState: UserState = { id: "", email: "", first_name: "", last_name: "", username: "", avatar_url: "", is_superuser: false, course_session_experts: [], loggedIn: false, language: defaultLanguage, }; async function setLocale(language: AvailableLanguages) { switch (language) { case "de": await import("dayjs/locale/de"); break; case "fr": await import("dayjs/locale/fr"); break; case "it": await import("dayjs/locale/it"); } dayjs.locale(language); setI18nLanguage(language); } export const useUserStore = defineStore({ id: "user", state: () => initialUserState as UserState, getters: { getFullName(): string { return `${this.first_name} ${this.last_name}`.trim(); }, }, actions: { handleLogin(username: string, password: string, next = "/") { if (username && password) { itPost("/api/core/login/", { username, password, }) .then((data) => { this.$state = data; this.loggedIn = true; log.debug("bust cache"); bustItGetCache(); log.debug(`redirect to ${next}`); window.location.href = next; }) .catch(() => { this.loggedIn = false; alert("Login failed"); }); } }, handleLogout() { Object.assign(this, initialUserState); itPost("/api/core/logout/", {}).then(() => { let redirectUrl; if (logoutRedirectUrl !== "") { redirectUrl = logoutRedirectUrl; } else { redirectUrl = "/"; } window.location.href = redirectUrl; }); }, async fetchUser() { const data = await itGetCached("/api/core/me/"); this.$state = data; this.loggedIn = true; await setLocale(data.language); }, async setUserLanguages(language: AvailableLanguages) { await setLocale(language); this.$state.language = language; await itPost("/api/core/me/", { language }, { method: "PUT" }); }, }, });