Files
CODE_ASSISTANT/2_frontend/src/shared/components/ProtectedRoute.tsx
T
lee-hyeon-cheolandClaude Fable 5.1 47d31dbe06 feat(app): 활성 창 캡쳐·캡쳐 목적지 선택·단축키 Ctrl+Alt 재배치 + UX 손질
- Ctrl+Alt+A/Z 맨 앞 창 통째 캡쳐(DWM 확장 프레임 경계), S/X 드래그 캡쳐. A/S 새 대화, Z/X 마지막 대화
- 캡쳐 후 창을 확실히 앞으로(AttachThreadInput), capture.image 에 목적지 path 실어 그 Composer 만 소비
- 드래그 선택영역 원본 밝기·더블버퍼(번쩍임) — code-assistant-v2 복사본에서 이식
- 단축키 Ctrl+Alt+Q/W: Eclipse·ADT·SAP GUI 바인딩 목록 대조해 비어 있는 조합으로
- 버튼 cursor:pointer(Tailwind v4), 가운데 스피너, 스니펫→챗 버튼, 스니펫 검색창 높이 84→88

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 16:34:48 +09:00

33 lines
1.2 KiB
TypeScript

import { useEffect } from "react"
import { Navigate, Outlet, useLocation } from "react-router-dom"
import { useMe } from "@/features/auth/hooks/useMe"
import { useAuthStore } from "@/features/auth/store/authStore"
import { PATHS } from "@/config/routes"
import { CenterSpinner } from "@/shared/components/CenterSpinner"
/**
* 저장된 user를 서버에서 확인한 뒤 보호 화면을 연다.
* 인증이 없으면 `/login?from=<원래 경로>` 로 redirect.
* `from`은 LoginForm에서 검증 후 사용 (외부 도메인·protocol-relative 차단).
*/
export default function ProtectedRoute() {
const user = useAuthStore((s) => s.user)
const clearUser = useAuthStore((s) => s.clearUser)
const me = useMe(user !== null)
const location = useLocation()
useEffect(() => {
if (me.isError) clearUser()
}, [clearUser, me.isError])
if (!user || me.isError) {
const from = `${location.pathname}${location.search}${location.hash}`
const query = from && from !== "/" ? `?from=${encodeURIComponent(from)}` : ""
return <Navigate to={`${PATHS.LOGIN}${query}`} replace />
}
if (me.isLoading) {
return <CenterSpinner label="로그인 확인 중" />
}
return <Outlet />
}