feat(auth): enhance logout and login flow with return URL handling

This commit is contained in:
2025-04-25 14:41:58 -04:00
parent 2c09be4465
commit e394c346ae
5 changed files with 53 additions and 11 deletions

View File

@@ -55,7 +55,7 @@ export function useClient() {
return client(originalRequest);
} catch (refreshError) {
console.error('Token refresh failed, logging out user:', refreshError);
await authStore.logout();
await authStore.logout('/login');
throw refreshError;
}
}

View File

@@ -94,6 +94,7 @@ const routes = [
name: 'login',
component: LoginView,
meta: { notAuthenticated: true },
props: (route) => ({ returnUrl: route.query.returnUrl || '/landing' })
},
{
path: '/profile',
@@ -119,11 +120,20 @@ router.beforeEach((to, from, next) => {
const authStore = useAuthStore();
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (!authStore.isAuthenticated) next({ name: 'login' });
if (!authStore.isAuthenticated) {
next({
name: 'login',
query: { returnUrl: to.fullPath }
});
} else {
next();
}
} else if (to.matched.some((record) => record.meta.notAuthenticated)) {
if (authStore.isAuthenticated) next({ name: 'landing' });
else next();
} else {
next();
}
next();
});
export default router;

View File

@@ -72,7 +72,7 @@ export const useAuthStore = defineStore(
// Clear any other auth-related data if needed
}
async function logout() {
async function logout(redirectTo = '/landing') {
try {
// Optionally call logout endpoint if you have one
// await clientApi.post('api/users/logout');
@@ -80,7 +80,7 @@ export const useAuthStore = defineStore(
console.error('Logout failed:', error);
} finally {
cleanTokens();
await router.push('/');
await router.push(redirectTo);
}
}
@@ -201,8 +201,15 @@ export const useAuthStore = defineStore(
// Only clear tokens and session storage after a failed refresh attempt
cleanTokens();
// Force a redirect to the login page
await router.push('/login');
// Get the current route to use as returnUrl
const currentRoute = router.currentRoute.value;
const returnUrl = currentRoute.fullPath;
// Force a redirect to the login page with returnUrl
await router.push({
name: 'login',
query: { returnUrl }
});
throw error;
}

View File

@@ -3,16 +3,30 @@ import {ref} from 'vue';
import {GoogleLogin} from "vue3-google-login";
import {useAuthStore} from '@/stores/authStore.js';
import {useI18n} from 'vue-i18n';
import {useRouter} from 'vue-router';
const {t} = useI18n();
const router = useRouter();
const authStore = useAuthStore();
const errorSnackBar = ref(false);
const props = defineProps({
returnUrl: {
type: String,
default: '/landing'
}
});
async function googleCallback(token) {
const response = await authStore.loginWithGoogle(JSON.stringify(token));
if (response !== true) {
try {
const response = await authStore.loginWithGoogle(JSON.stringify(token));
if (response === true) {
await router.push(props.returnUrl);
} else {
errorSnackBar.value = true;
}
} catch (error) {
console.error('Login failed:', error);
errorSnackBar.value = true;
}
}

View File

@@ -4,9 +4,12 @@ import {useAuthStore} from "@/stores/authStore.js";
import {useCreatorProfileStore} from "@/stores/creatorProfileStore.js";
import {useUserProfileStore} from "@/stores/userProfileStore.js";
import {useLanguageStore} from "@/stores/languageStore.js";
import {useRouter, useRoute} from 'vue-router';
const {locale, t} = useI18n();
const languageStore = useLanguageStore();
const router = useRouter();
const route = useRoute();
const userProfileStore = useUserProfileStore();
const creatorProfileStore = useCreatorProfileStore();
@@ -18,6 +21,14 @@ function toggleLanguage() {
const nextIndex = (currentIndex + 1) % languages.length;
languageStore.setLocale(languages[nextIndex]);
}
function handleLogout() {
// Check if current route requires authentication
const requiresAuth = route.matched.some(record => record.meta.requiresAuth);
// If on a protected page, redirect to landing, otherwise stay on current page
const redirectTo = requiresAuth ? '/landing' : route.fullPath;
authStore.logout(redirectTo);
}
</script>
<template>
@@ -85,7 +96,7 @@ function toggleLanguage() {
</template>
<div v-else>
<button class="menu-item-action"
@click="authStore.logout">
@click="handleLogout">
<i class="mdi mdi-logout"></i>
<span class="label">{{ t('sidebar.signOut') }}</span>
</button>