Skip to content

Commit fd31cf3

Browse files
authored
[feat] 자동 로그아웃 처리(4시간) (#115)
1 parent 27c5a27 commit fd31cf3

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

src/app/layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Header from '@/shared/components/header/Header';
55
import FooterWrapper from '@/shared/components/footer/FooterWrapper';
66
import ScrollTopBtnWrapper from '@/shared/components/scroll-top/ScrollTopBtnWrapper';
77
import KaKaoScript from './api/kakao/KaKaoScript';
8+
import IdleHandler from '@/domains/login/components/IdleHandler';
89

910
export const metadata: Metadata = {
1011
title: { default: 'SSOUL', template: 'SSOUL | %s' },
@@ -21,6 +22,7 @@ export default function RootLayout({
2122
<html lang="ko-KR">
2223
<body className="relative flex flex-col min-h-screen">
2324
<Header />
25+
<IdleHandler />
2426
<main className="flex flex-1 pt-[2.75rem] md:pt-[3.75rem]">{children}</main>
2527
<FooterWrapper />
2628

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use client';
2+
3+
import { useIdleLogout } from '../hook/useIdleLogout';
4+
5+
function IdleHandler() {
6+
useIdleLogout();
7+
return null;
8+
}
9+
export default IdleHandler;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use client';
2+
3+
import { useCallback, useEffect, useRef } from 'react';
4+
import { useLogout } from './useLogout';
5+
import { useToast } from '@/shared/hook/useToast';
6+
import { useAuthStore } from '@/domains/shared/store/auth';
7+
8+
const IDLE_TIMEOUT = 4 * 60 * 60 * 1000;
9+
10+
export const useIdleLogout = () => {
11+
const handleLogout = useLogout();
12+
const timerRef = useRef<NodeJS.Timeout | null>(null);
13+
const warningTimerRef = useRef<NodeJS.Timeout | null>(null);
14+
const { toastInfo } = useToast();
15+
const { isLoggedIn } = useAuthStore();
16+
17+
const resetTimer = useCallback(() => {
18+
if (!isLoggedIn) return;
19+
if (timerRef.current) clearTimeout(timerRef.current);
20+
if (warningTimerRef.current) clearTimeout(warningTimerRef.current);
21+
22+
timerRef.current = setTimeout(() => {
23+
toastInfo('5초 뒤 자동 로그아웃 예정 \n 움직이면 자동 로그아웃 취소됩니다.');
24+
warningTimerRef.current = setTimeout(() => handleLogout(), 5000);
25+
}, IDLE_TIMEOUT);
26+
}, [isLoggedIn, handleLogout, toastInfo]);
27+
28+
useEffect(() => {
29+
const events = ['mousemove', 'keydown', 'mousedown', 'touchstart'];
30+
events.forEach((e) => window.addEventListener(e, resetTimer));
31+
32+
resetTimer();
33+
34+
return () => {
35+
if (timerRef.current) clearTimeout(timerRef.current);
36+
if (warningTimerRef.current) clearTimeout(warningTimerRef.current);
37+
events.forEach((e) => window.removeEventListener(e, resetTimer));
38+
};
39+
}, [resetTimer]);
40+
};

0 commit comments

Comments
 (0)