habits.andr33v.ru/app/composables/useAuth.ts

66 lines
1.7 KiB
TypeScript

// /composables/useAuth.ts
interface User {
id: string;
email: string;
nickname: string;
}
export function useAuth() {
// 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>('user', () => null);
const initialized = useState('auth_initialized', () => false);
const loading = ref(false); // This is a local, non-shared loading ref for fetchMe's internal use
const api = useApi();
const isAuthenticated = computed(() => !!user.value);
const fetchMe = async () => {
if (initialized.value) return;
loading.value = true;
initialized.value = true;
try {
user.value = await api<User>('/auth/me', { method: 'GET' });
} catch (error) {
user.value = null; // Silently set user to null
} finally {
loading.value = false;
}
};
const login = async (email, password) => {
// 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();
};
const logout = async () => {
try {
await api('/auth/logout', { method: 'POST' });
} finally {
// Always clear state and redirect, regardless of API call success.
user.value = null;
initialized.value = false;
await navigateTo('/login');
}
};
// Expose the state and methods.
return {
user,
isAuthenticated,
initialized,
fetchMe,
login,
logout,
};
}