"use client"; import React, { createContext, useContext, useEffect, useState } from "react"; import { useAuth } from "@/hooks/useAuth"; import { SessionManager, initSessionManager, cleanupSessionManager, formatTime } from "@/lib/sessionManager"; interface AuthContextType { sessionManager: SessionManager | null; showSessionWarning: boolean; warningTime: number; } const AuthContext = createContext(undefined); interface AuthProviderProps { children: React.ReactNode; } /** * 모바일 환경 감지 함수 * WebView, 모바일 브라우저 등을 감지 */ function isMobileEnvironment(): boolean { if (typeof window === "undefined") return false; const userAgent = navigator.userAgent.toLowerCase(); // 모바일 기기 감지 const isMobileDevice = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent); // WebView 감지 (앱 내 브라우저) const isWebView = /wv/.test(userAgent) || // Android WebView /webview/.test(userAgent) || (window as unknown as { webkit?: unknown }).webkit !== undefined || // iOS WKWebView /fb_iab|fban|fbav/.test(userAgent) || // Facebook 앱 내 브라우저 /instagram/.test(userAgent) || // Instagram 앱 내 브라우저 /kakaotalk/.test(userAgent) || // 카카오톡 앱 내 브라우저 /naver/.test(userAgent); // 네이버 앱 내 브라우저 return isMobileDevice || isWebView; } /** * 인증 컨텍스트 프로바이더 * 전역 세션 관리 및 세션 만료 경고 처리 */ export function AuthProvider({ children }: AuthProviderProps) { const { isLoggedIn, logout } = useAuth(); const [sessionManager, setSessionManager] = useState(null); const [showSessionWarning, setShowSessionWarning] = useState(false); const [warningTime, setWarningTime] = useState(0); // 세션 매니저 초기화 및 정리 useEffect(() => { if (isLoggedIn) { // 모바일 환경 여부에 따라 타임아웃 시간 조정 const isMobile = isMobileEnvironment(); // 모바일: 24시간 (JWT 토큰 만료 시간과 동일), 데스크톱: 30분 const maxInactiveTime = isMobile ? 86400000 : 1800000; // 모바일: 1시간 전 경고, 데스크톱: 5분 전 경고 const warningTimeConfig = isMobile ? 3600000 : 300000; // 세션 매니저 초기화 const manager = initSessionManager( { checkInterval: 60000, // 1분마다 체크 warningTime: warningTimeConfig, maxInactiveTime: maxInactiveTime, }, { onWarning: (remainingTime: number) => { console.log(`세션 만료 경고: ${formatTime(remainingTime)} 남음`); setWarningTime(remainingTime); setShowSessionWarning(true); }, onExpiry: () => { console.log("세션이 만료되어 자동 로그아웃됩니다"); setShowSessionWarning(false); logout(); }, onActivity: () => { // 활동 감지 시 경고 숨김 if (showSessionWarning) { setShowSessionWarning(false); } }, }, ); setSessionManager(manager); manager.start(); return () => { manager.stop(); cleanupSessionManager(); setSessionManager(null); }; } else { // 로그인되지 않은 경우 세션 매니저 정리 cleanupSessionManager(); setSessionManager(null); setShowSessionWarning(false); } }, [isLoggedIn, logout, showSessionWarning]); const contextValue: AuthContextType = { sessionManager, showSessionWarning, warningTime, }; return {children}; } /** * 인증 컨텍스트 사용 훅 */ export function useAuthContext() { const context = useContext(AuthContext); if (context === undefined) { throw new Error("useAuthContext must be used within an AuthProvider"); } return context; } export default AuthProvider;