- shared/auth 모듈: AuthProvider, ProtectedRoute, useAuth, authApi - 페이지: LoginPage(Google OAuth), PendingPage, DeniedPage - WING_PERMIT 역할 기반 접근 제어 - Topbar에 사용자 이름 + 로그아웃 버튼 추가 - App.tsx에 react-router 라우팅 + AuthProvider 래핑 - DEV 모드 Mock 로그인 지원 (김개발) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
import { Navigate } from 'react-router';
|
|
import { useAuth } from '../../shared/auth';
|
|
|
|
export function DeniedPage() {
|
|
const { user, loading, logout } = useAuth();
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="auth-loading">
|
|
<div className="auth-loading__spinner" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!user) {
|
|
return <Navigate to="/login" replace />;
|
|
}
|
|
|
|
const isRejectedOrDisabled =
|
|
user.status === 'REJECTED' || user.status === 'DISABLED';
|
|
const hasWingPermit = user.roles.some((r) => r.name === 'WING_PERMIT');
|
|
|
|
return (
|
|
<div className="auth-page">
|
|
<div className="auth-card">
|
|
<div className="auth-status-icon">🚫</div>
|
|
<div className="auth-title">접근 불가</div>
|
|
<div className="auth-message">
|
|
{isRejectedOrDisabled
|
|
? `계정이 ${user.status === 'REJECTED' ? '거절' : '비활성화'}되었습니다.`
|
|
: !hasWingPermit
|
|
? 'WING 대시보드 접근 권한이 없습니다. 관리자에게 WING_PERMIT 역할을 요청하세요.'
|
|
: '접근이 거부되었습니다.'}
|
|
</div>
|
|
<div className="auth-message" style={{ fontSize: 11, marginTop: 8 }}>
|
|
{user.email}
|
|
</div>
|
|
<button className="auth-link-btn" onClick={logout}>
|
|
로그아웃
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|