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

85 lines
2.4 KiB
TypeScript

// /composables/useAuth.ts
interface User {
id: string;
email: string;
nickname: string;
avatar: string | null;
coins: number;
exp: number;
dailyStreak: number;
soundOn: boolean;
confettiOn: boolean;
createdAt: string;
updatedAt: 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 () => {
// This function can be called multiple times, but the logic inside
// will only run once thanks to the initialized flag.
if (initialized.value) return;
loading.value = true;
try {
// The backend returns the user object nested under a 'user' key.
const response = await api<{ user: User }>('/auth/me', { method: 'GET' });
user.value = response.user; // Correctly assign the nested user object
} catch (error) {
user.value = null; // Silently set user to null on 401
} finally {
loading.value = false;
initialized.value = true; // Mark as initialized after the first attempt
}
};
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');
}
};
const updateUser = (partialUser: Partial<User>) => {
if (user.value) {
user.value = { ...user.value, ...partialUser };
}
};
// Expose the state and methods.
return {
user,
isAuthenticated,
initialized,
fetchMe,
login,
logout,
updateUser,
};
}