vbv/client/src/stores/user.ts

136 lines
3.5 KiB
TypeScript

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" });
},
},
});