gc-guide/src/auth/AuthProvider.tsx
htlee 9e86244e96 feat: 관리자 가입 설정 페이지 추가
자동승인 토글 + 기본 부여 롤 설정 UI 구현

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:25:53 +09:00

96 lines
2.6 KiB
TypeScript

import {
useCallback,
useEffect,
useMemo,
useState,
type ReactNode,
} from 'react';
import type { AuthResponse, User } from '../types';
import { api } from '../utils/api';
import { AuthContext } from './AuthContext';
const DEV_MOCK_USER: User = {
id: 1,
email: 'htlee@gcsc.co.kr',
name: '김개발 (DEV)',
avatarUrl: null,
status: 'ACTIVE',
isAdmin: true,
roles: [{ id: 1, name: 'ADMIN', description: '관리자', urlPatterns: ['/**'], defaultGrant: false }],
createdAt: new Date().toISOString(),
lastLoginAt: new Date().toISOString(),
};
function isDevMockSession(): boolean {
return import.meta.env.DEV && localStorage.getItem('dev-user') === 'true';
}
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(() =>
isDevMockSession() ? DEV_MOCK_USER : null,
);
const [token, setToken] = useState<string | null>(
() => localStorage.getItem('token'),
);
const [initialized, setInitialized] = useState(
() => isDevMockSession() || !localStorage.getItem('token'),
);
const logout = useCallback(() => {
const hadToken = !!localStorage.getItem('token') && !isDevMockSession();
localStorage.removeItem('token');
localStorage.removeItem('dev-user');
setToken(null);
setUser(null);
if (hadToken) {
api.post('/auth/logout').catch(() => {});
}
}, []);
const devLogin = useCallback(() => {
localStorage.setItem('dev-user', 'true');
localStorage.setItem('token', 'dev-mock-token');
setToken('dev-mock-token');
setUser(DEV_MOCK_USER);
setInitialized(true);
}, []);
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 || isDevMockSession()) return;
let cancelled = false;
api
.get<User>('/auth/me')
.then((data) => {
if (!cancelled) setUser(data);
})
.catch(() => {
if (!cancelled) logout();
})
.finally(() => {
if (!cancelled) setInitialized(true);
});
return () => {
cancelled = true;
};
}, [token, logout]);
const loading = !initialized;
const value = useMemo(
() => ({ user, token, loading, login, devLogin: import.meta.env.DEV ? devLogin : undefined, logout }),
[user, token, loading, login, devLogin, logout],
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}