Move session management into session store

Trying to get rid of the redirect to signin on any page refresh
This commit is contained in:
Eli Ribble 2026-04-17 14:52:02 +00:00
parent bf156eaf7f
commit efa01cffc2
No known key found for this signature in database
8 changed files with 34 additions and 69 deletions

View file

@ -13,12 +13,11 @@ onMounted(() => {
session
.get()
.then((session: Session) => {
console.log("session loaded", session);
console.log("session loaded by AppSync", session);
})
.catch((e) => {
console.log("root session not loaded", e);
router.push("/signin");
});
console.log("home mounted");
});
</script>

View file

@ -4,6 +4,7 @@ import router from "@/router";
class ApiClient {
private client: AxiosInstance;
private _hasSession: boolean = false;
private _isAuthenticated: boolean = false;
constructor() {
@ -40,14 +41,6 @@ class ApiClient {
);
}
get isAuthenticated(): boolean {
return this._isAuthenticated;
}
setAuthenticated(value: boolean): void {
this._isAuthenticated = value;
}
async JSONGet<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
const response = await this.client.get<T>(url, {
...config,

View file

@ -1,15 +1,9 @@
<template>
<div id="content">
<div v-if="session.loading">Loading...</div>
<div v-else-if="session.error">Error: {{ session.error }}</div>
<slot />
</div>
</template>
<script setup lang="ts">
import { useSessionStore } from "@/store/session";
const session = useSessionStore();
</script>
<script setup lang="ts"></script>
<style scoped></style>

View file

@ -1,5 +1,7 @@
import { createRouter, createWebHistory } from "vue-router";
import type { RouteRecordRaw } from "vue-router";
import { useSessionStore } from "@/store/session";
import Home from "@/view/Home.vue";
import Authenticated from "@/view/Authenticated.vue";
import Communication from "@/view/Communication.vue";
@ -43,53 +45,44 @@ const routes: RouteRecordRaw[] = [
path: "/_/communication",
name: "Communication",
component: Communication,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration",
name: "Configuration",
component: ConfigurationRoot,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration/integration",
name: "Integration Configuration",
component: ConfigurationIntegration,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration/integration/arcgis",
name: "Arcgis Integration Configuration",
component: ConfigurationIntegrationArcgis,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration/organization",
name: "Organization Configuration",
component: ConfigurationOrganization,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration/pesticide",
name: "Pesticide Configuration",
component: ConfigurationPesticide,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration/pesticide/add",
name: "Pesticide Add",
component: ConfigurationPesticideAdd,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration/upload",
name: "Upload Configuration",
component: ConfigurationUpload,
meta: { requiresAuth: true, showSidebar: true },
},
{
component: ConfigurationUploadDetail,
meta: { requiresAuth: true, showSidebar: true },
name: "Upload Detail",
path: "/_/configuration/upload/:id",
props: (route) => ({
@ -100,35 +93,29 @@ const routes: RouteRecordRaw[] = [
path: "/_/configuration/upload/pool",
name: "Pool Upload",
component: ConfigurationUploadPool,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration/upload/pool/custom",
name: "Custom Pool Upload",
component: ConfigurationUploadPoolCustom,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration/upload/pool/flyover",
name: "Flyover Upload",
component: ConfigurationUploadPoolFlyover,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration/user",
name: "User Configuration",
component: ConfigurationUser,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/configuration/user/add",
name: "User Add Configuration",
component: ConfigurationUserAdd,
meta: { requiresAuth: true, showSidebar: true },
},
{
component: ConfigurationUserEdit,
meta: { requiresAuth: true, showSidebar: true },
name: "User Edit",
path: "/_/configuration/user/:id",
props: (route) => ({
@ -144,49 +131,41 @@ const routes: RouteRecordRaw[] = [
path: "/_/intelligence",
name: "Intelligence",
component: Intelligence,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/oauth/refresh/arcgis",
name: "Arcgis OAuth Refresh",
component: OAuthRefreshArcgis,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/operations",
name: "Operations",
component: Operations,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/planning",
name: "Planning",
component: Planning,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/review",
name: "Review",
component: ReviewRoot,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/review/pool",
name: "Pool Review",
component: ReviewPool,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/review/site",
name: "Site Review",
component: ReviewSite,
meta: { requiresAuth: true, showSidebar: true },
},
{
path: "/_/sudo",
name: "Sudo",
component: Sudo,
meta: { requiresAuth: true, showSidebar: true },
},
],
component: Authenticated,
@ -218,21 +197,19 @@ export const router = createRouter({
// Global navigation guard
router.beforeEach(async (to, from) => {
const requiresAuth = to.matched.some((record) => record.meta.requiresAuth);
if (requiresAuth) {
try {
// Check if user is authenticated (could be an API call)
if (!apiClient.isAuthenticated) {
return "/signin";
} else {
return;
}
} catch (error) {
console.log("check auth failed");
return "/signin";
}
if (to.fullPath == "/signin") {
return;
}
const storeSession = useSessionStore();
try {
if (!storeSession.isLoading && !storeSession.isAuthenticated) {
console.log("sending to signin because we're not authenticated");
return `/signin?next=${from.fullPath}`;
}
} catch (error) {
console.log("check auth failed");
}
return;
});
export default router;

View file

@ -12,9 +12,11 @@ import { apiClient } from "@/client";
export const useSessionStore = defineStore("session", () => {
// State
const hasSession = ref<boolean>(false);
const isAuthenticated = ref<boolean>(false);
const isLoading = ref(true);
const impersonating = ref<string | null>(null);
const error = ref<string | null>(null);
const loading = ref(true);
const current = ref<Session | null>(null);
const notification_counts = ref<SessionNotificationCounts | null>(null);
const ongoingFetch = ref<Promise<Session> | null>(null);
@ -31,12 +33,11 @@ export const useSessionStore = defineStore("session", () => {
// Actions
async function fetchSession(): Promise<Session> {
loading.value = true;
error.value = null;
try {
const data: Session = await apiClient.JSONGet("/api/session");
apiClient.setAuthenticated(true);
isAuthenticated.value = true;
impersonating.value = data.impersonating || null;
notification_counts.value = data.notification_counts;
organization.value = data.organization;
@ -44,19 +45,19 @@ export const useSessionStore = defineStore("session", () => {
urls.value = data.urls;
return data;
} catch (e) {
apiClient.setAuthenticated(false);
error.value = e instanceof Error ? e.message : "an error ocurred";
console.error("Error fetching user:", e);
throw new Error(error.value);
} finally {
loading.value = false;
hasSession.value = true;
isLoading.value = false;
console.log("no longer loading session");
}
}
async function isAuthenticated(): Promise<boolean> {
console.log("pretend check user auth");
return true;
async function getAuthenticated(): Promise<boolean> {
await get();
return isAuthenticated.value;
}
async function get(): Promise<Session> {
@ -74,13 +75,17 @@ export const useSessionStore = defineStore("session", () => {
return s;
}
async function signout(): Promise<void> {
isAuthenticated.value = false;
apiClient.JSONPost("/api/signout", {});
}
return {
// State
error,
getAuthenticated,
hasSession,
impersonating,
loading,
isAuthenticated,
isLoading,
notification_counts,
organization,
self,
@ -88,7 +93,6 @@ export const useSessionStore = defineStore("session", () => {
// Actions
fetchSession,
get,
isAuthenticated,
signout,
};
});

View file

@ -6,7 +6,7 @@
</style>
<template>
<div class="app-container">
<template v-if="session.loading">Loading...</template>
<template v-if="session.isLoading">Loading...</template>
<template v-else-if="session.error">Error: {{ session.error }}</template>
<template v-else>
<Sidebar />

View file

@ -12,13 +12,12 @@ onMounted(() => {
session
.get()
.then((session: Session) => {
console.log("session loaded", session);
console.log("hit home with a valid session, going to dash");
router.push("/_/dash");
})
.catch((e) => {
console.log("root session not loaded", e);
console.log("hit home with no session, going to signin");
router.push("/signin");
});
console.log("home mounted");
});
</script>

View file

@ -10,7 +10,6 @@ import { useSessionStore } from "@/store/session";
const session = useSessionStore();
onMounted(() => {
session.signout().then(() => {
apiClient.setAuthenticated(false);
router.push("/signin");
});
});