81 lines
1.9 KiB
TypeScript
81 lines
1.9 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useRouter } from 'next/navigation';
|
||
|
|
import { useEffect, useState, useCallback } from 'react';
|
||
|
|
import {
|
||
|
|
login as apiLogin,
|
||
|
|
getCurrentUser,
|
||
|
|
setTokens,
|
||
|
|
clearTokens,
|
||
|
|
isAuthenticated,
|
||
|
|
type UserResponse,
|
||
|
|
type ApiError,
|
||
|
|
} from './api';
|
||
|
|
|
||
|
|
export interface AuthState {
|
||
|
|
user: UserResponse | null;
|
||
|
|
loading: boolean;
|
||
|
|
error: string | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useAuth() {
|
||
|
|
const [state, setState] = useState<AuthState>({
|
||
|
|
user: null,
|
||
|
|
loading: true,
|
||
|
|
error: null,
|
||
|
|
});
|
||
|
|
|
||
|
|
const fetchUser = useCallback(async () => {
|
||
|
|
if (!isAuthenticated()) {
|
||
|
|
setState({ user: null, loading: false, error: null });
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
const user = await getCurrentUser();
|
||
|
|
setState({ user, loading: false, error: null });
|
||
|
|
} catch {
|
||
|
|
clearTokens();
|
||
|
|
setState({ user: null, loading: false, error: 'Session expired' });
|
||
|
|
}
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
fetchUser();
|
||
|
|
}, [fetchUser]);
|
||
|
|
|
||
|
|
const login = useCallback(async (email: string, password: string) => {
|
||
|
|
setState({ user: null, loading: true, error: null });
|
||
|
|
try {
|
||
|
|
const tokens = await apiLogin(email, password);
|
||
|
|
setTokens(tokens);
|
||
|
|
const user = await getCurrentUser();
|
||
|
|
setState({ user, loading: false, error: null });
|
||
|
|
return user;
|
||
|
|
} catch (err) {
|
||
|
|
const message = (err as ApiError)?.error?.message || 'Login failed';
|
||
|
|
setState({ user: null, loading: false, error: message });
|
||
|
|
throw err;
|
||
|
|
}
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const logout = useCallback(() => {
|
||
|
|
clearTokens();
|
||
|
|
setState({ user: null, loading: false, error: null });
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return { ...state, login, logout, refresh: fetchUser };
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useRequireAuth() {
|
||
|
|
const auth = useAuth();
|
||
|
|
const router = useRouter();
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (!auth.loading && !auth.user) {
|
||
|
|
router.push('/login');
|
||
|
|
}
|
||
|
|
}, [auth.loading, auth.user, router]);
|
||
|
|
|
||
|
|
return auth;
|
||
|
|
}
|