diff --git a/app/composables/useAuth.ts b/app/composables/useAuth.ts index 3a3c66a..fefc069 100644 --- a/app/composables/useAuth.ts +++ b/app/composables/useAuth.ts @@ -1,101 +1,65 @@ // /composables/useAuth.ts -// Define User interface interface User { id: string; email: string; nickname: string; } -/** - * Composable for authentication management. - * All state is managed by Nuxt's useState to ensure it's shared and SSR-safe. - */ export function useAuth() { - // --- State --- - // All state is defined here, inside the composable function. - // Nuxt's useState ensures this state is a singleton across the app. + // All Nuxt composables that require instance access MUST be called inside the setup function. + // useState is how we create shared, SSR-safe state in Nuxt. const user = useState('user', () => null); - const loading = useState('auth_loading', () => false); const initialized = useState('auth_initialized', () => false); + const loading = ref(false); // This is a local, non-shared loading ref for fetchMe's internal use - // --- Composables --- const api = useApi(); - - // --- Computed Properties --- const isAuthenticated = computed(() => !!user.value); - // --- Methods --- - - /** - * Fetches the current user from the backend. - * Runs only once, guarded by the 'initialized' state. - */ const fetchMe = async () => { - if (initialized.value) { - return; - } + if (initialized.value) return; loading.value = true; initialized.value = true; try { - const fetchedUser = await api('/auth/me', { method: 'GET' }); - user.value = fetchedUser; + user.value = await api('/auth/me', { method: 'GET' }); } catch (error) { - user.value = null; // Silently handle 401s or other errors + user.value = null; // Silently set user to null } finally { loading.value = false; } }; - /** - * Logs the user in and fetches their data on success. - */ const login = async (email, password) => { - loading.value = true; - try { - await api('/auth/login', { - method: 'POST', - body: { email, password }, - }); - - // We must re-fetch the user after logging in. - // Resetting 'initialized' allows fetchMe to run again. - initialized.value = false; - await fetchMe(); - - await navigateTo('/'); - } catch (error) { - console.error('Login failed:', error); - throw error; // Re-throw to allow the UI to handle it - } finally { - loading.value = false; - } + // The calling component is responsible for its own loading state. + // This function just performs the action. + await api('/auth/login', { + method: 'POST', + body: { email, password }, + }); + // After a successful login, allow a re-fetch of the user state. + initialized.value = false; + await fetchMe(); }; - /** - * Logs the user out. - */ const logout = async () => { - loading.value = true; try { await api('/auth/logout', { method: 'POST' }); - } catch (error) { - console.error('Logout API call failed, proceeding with client-side logout:', error); } finally { + // Always clear state and redirect, regardless of API call success. user.value = null; - initialized.value = false; // Allow re-fetch on next app load/login - loading.value = false; + initialized.value = false; await navigateTo('/login'); } }; + // Expose the state and methods. return { user, - loading, isAuthenticated, + initialized, fetchMe, login, logout, }; -} \ No newline at end of file +} diff --git a/app/pages/habits.vue b/app/pages/habits.vue index 7323f83..8114e42 100644 --- a/app/pages/habits.vue +++ b/app/pages/habits.vue @@ -1,45 +1,163 @@ diff --git a/app/pages/index.vue b/app/pages/index.vue index 02a629e..9b7839c 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -1,6 +1,9 @@