gc-guide/src/auth/AuthProvider.tsx

71 lines
1.6 KiB
TypeScript
Raw Normal View 히스토리

import {
createContext,
useCallback,
useEffect,
useMemo,
useState,
type ReactNode,
} from 'react';
import type { AuthResponse, User } from '../types';
import { api } from '../utils/api';
interface AuthContextValue {
user: User | null;
token: string | null;
loading: boolean;
login: (googleToken: string) => Promise<void>;
logout: () => void;
}
export const AuthContext = createContext<AuthContextValue>({
user: null,
token: null,
loading: true,
login: async () => {},
logout: () => {},
});
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [token, setToken] = useState<string | null>(
() => localStorage.getItem('token'),
);
const [loading, setLoading] = useState(true);
const logout = useCallback(() => {
localStorage.removeItem('token');
setToken(null);
setUser(null);
}, []);
const login = useCallback(async (googleToken: string) => {
const res = await api.post<AuthResponse>('/auth/google', {
idToken: googleToken,
});
localStorage.setItem('token', res.token);
setToken(res.token);
setUser(res.user);
}, []);
useEffect(() => {
if (!token) {
setLoading(false);
return;
}
api
.get<User>('/auth/me')
.then(setUser)
.catch(() => {
logout();
})
.finally(() => setLoading(false));
}, [token, logout]);
const value = useMemo(
() => ({ user, token, loading, login, logout }),
[user, token, loading, login, logout],
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}