feeds-fun
Version:
Frontend for the Feeds Fun — web-based news reader
122 lines (96 loc) • 3.38 kB
text/typescript
import {ref, watch, computed} from "vue";
import {useRouter, useRoute} from "vue-router";
import {defineStore} from "pinia";
import {computedAsync, useBroadcastChannel} from "@vueuse/core";
import {Timer} from "@/logic/timer";
import * as settings from "@/logic/settings";
import * as api from "@/logic/api";
import * as e from "@/logic/enums";
const GLOBAL_BROADCAST_CHANNEL_ID = "ffun-global-event-channel";
const GLOBAL_BROADCAST_EVENT_LOGOUT_COMPLETED = "logoutCompleted";
const LOGGED_OUT_QUERY_MARKER = "logged-out";
export const useGlobalState = defineStore("globalState", () => {
const router = useRouter();
const route = useRoute();
const infoRefreshMarker = ref(0);
function refreshAuthState() {
infoRefreshMarker.value++;
}
////////////////////////////////
// sync login state between tabs
////////////////////////////////
const globalChannel = useBroadcastChannel<any, any>({name: GLOBAL_BROADCAST_CHANNEL_ID});
watch(globalChannel.data, (event) => {
if (event.type === GLOBAL_BROADCAST_EVENT_LOGOUT_COMPLETED) {
refreshAuthState();
}
});
// check if the marker is in the URL (means that user has just redirected after logout)
watch(route, (r) => {
if (!(LOGGED_OUT_QUERY_MARKER in r.query)) {
return;
}
globalChannel.post({type: GLOBAL_BROADCAST_EVENT_LOGOUT_COMPLETED});
// remove the marker from the URL
const query = {...r.query};
delete query[LOGGED_OUT_QUERY_MARKER];
router.replace({query});
});
////////////////////////////////
// Periodic check auth state by timer
const authStateRefresher = new Timer(refreshAuthState, settings.authRefreshInterval);
// Check auth state on the particular events
// do not check "focus" and "visibilitychange" — they are too noisy
window.addEventListener("online", refreshAuthState);
window.addEventListener("pageshow", (event) => {
if (event.persisted) {
// BFCache restore (the user goes Back/Forward and the browser instantly revives a frozen snapshot).
refreshAuthState();
}
});
const info = computedAsync(async () => {
infoRefreshMarker.value;
return await api.getInfo();
}, null);
const userId = computedAsync(async () => {
infoRefreshMarker.value;
let userData = await api.getUser();
return userData ? userData.userId : null;
}, "unknown");
const isSingleUserMode = computed(() => {
return info.value ? info.value.singleUserMode : false;
});
const loginState = computed(() => {
if (userId.value === "unknown") {
return e.LoginState.Unknown;
}
return userId.value ? e.LoginState.LoggedIn : e.LoginState.LoggedOut;
});
const loginUnknown = computed(() => {
return loginState.value === e.LoginState.Unknown;
});
const loginConfirmed = computed(() => {
return loginState.value === e.LoginState.LoggedIn;
});
const logoutConfirmed = computed(() => {
return loginState.value === e.LoginState.LoggedOut;
});
function logout() {
if (isSingleUserMode.value) {
// In single user mode the user is always "logged in"
return;
}
api.logoutRedirect();
// TODO: we may want to notify other tabs about logout event
}
return {
userId,
isSingleUserMode,
loginState,
loginUnknown,
loginConfirmed,
logoutConfirmed,
refreshAuthState,
logout
};
});