From 1a632338374f75ae9666cdff817dd686d887acbd Mon Sep 17 00:00:00 2001 From: novice1993 Date: Fri, 22 Sep 2023 02:31:51 +0900 Subject: [PATCH] =?UTF-8?q?[Refactor]=20=EC=9E=90=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=95=84=EC=9B=83=20=EC=BD=94=EB=93=9C=20=EA=B0=84?= =?UTF-8?q?=EC=86=8C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 자동 로그아웃 관련 모둘형 함수 생성하여 코드 간소화 (utils 디렉토리에 분류 후, export 하여 활용) - 이외 변경 사항 : 거래시간 제한 코드 주석처리 (익일 프로젝트 시연 목적, 추후 복구 예정) Issues #122 --- client/src/components/Logins/EmailLogin.tsx | 50 +---- .../StockOrderSection/StockOrder.tsx | 20 +- client/src/page/MainPage.tsx | 205 +++--------------- client/src/utils/README.md | 0 client/src/utils/setAutoLogoutAlarm.ts | 120 ++++++++++ 5 files changed, 162 insertions(+), 233 deletions(-) delete mode 100644 client/src/utils/README.md create mode 100644 client/src/utils/setAutoLogoutAlarm.ts diff --git a/client/src/components/Logins/EmailLogin.tsx b/client/src/components/Logins/EmailLogin.tsx index f34c5ac0..e47e8af2 100644 --- a/client/src/components/Logins/EmailLogin.tsx +++ b/client/src/components/Logins/EmailLogin.tsx @@ -1,10 +1,10 @@ import axios from "axios"; import styled from "styled-components"; import React, { useState } from "react"; -import { toast } from "react-toastify"; import { setLoginState } from "../../reducer/member/loginSlice"; -import { setLogoutState } from "../../reducer/member/loginSlice"; import { useDispatch } from "react-redux"; +import setAutoLogoutAlarm from "../../utils/setAutoLogoutAlarm"; +import { secondAlarmTime, lastAlarmTime } from "../../utils/setAutoLogoutAlarm"; const EmailLoginModal: React.FC = ({ onClose, onSignup }) => { const titleText = "이메일로 로그인"; @@ -56,51 +56,7 @@ const EmailLoginModal: React.FC = ({ onClose, onSignup }) if (refreshToken) sessionStorage.setItem("refreshToken", refreshToken); dispatch(setLoginState()); - const toastStyle = { - fontSize: "15px", - fontWeight: 350, - color: "black", - }; - - // 로그인 유지시긴 알림 - toast.warning("로그인 상태는 30분 동안 유지됩니다", { - style: toastStyle, - position: "top-center", - }); - - // 로그아웃 알림 1차 설정 + 이때 시간 저장 - const settingTime01 = 1000 * 60 * 29; // 29분 - const settingTime02 = 1000 * 60; // 1분 - const logoutAlarmTime01 = Date.now(); // 1차 알람 호출한 시간 - sessionStorage.setItem("logoutAlarmTime01", `${logoutAlarmTime01}`); // 세션 스토리지에 저장 - - setTimeout(() => { - // 첫번째 알람 실행되었으므로 -> 첫번째 시간기록 삭제 - sessionStorage.removeItem("logoutAlarmTime01"); - - toast.warning("1분 뒤 로그아웃 처리됩니다", { - style: toastStyle, - position: "top-center", - }); - - // 2차 알람 및 로그아웃 처리 + 토큰 삭제 - const logoutAlarmTime02 = Date.now(); // 2차 알람 호출한 시간 - sessionStorage.setItem("logoutAlarmTime02", `${logoutAlarmTime02}`); - - setTimeout(() => { - // 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제 - sessionStorage.removeItem("logoutAlarmTime02"); - - dispatch(setLogoutState()); - sessionStorage.removeItem("accessToken"); - sessionStorage.removeItem("refreshToken"); - - toast.warning("로그아웃 처리되었습니다", { - style: toastStyle, - position: "top-center", - }); - }, settingTime02); - }, settingTime01); + setAutoLogoutAlarm(dispatch, "first", secondAlarmTime, lastAlarmTime); onClose(); } else { diff --git a/client/src/components/StockOrderSection/StockOrder.tsx b/client/src/components/StockOrderSection/StockOrder.tsx index f6012e36..25de2dff 100644 --- a/client/src/components/StockOrderSection/StockOrder.tsx +++ b/client/src/components/StockOrderSection/StockOrder.tsx @@ -1,5 +1,5 @@ import { useSelector, useDispatch } from "react-redux"; -import { isHoliday } from "@hyunbinseo/holidays-kr"; +// import { isHoliday } from "@hyunbinseo/holidays-kr"; import { setStockOrderVolume } from "../../reducer/StockOrderVolume-Reducer"; import { closeDecisionWindow } from "../../reducer/SetDecisionWindow-Reducer"; import { styled } from "styled-components"; @@ -123,22 +123,22 @@ const StockOrder = ({ corpName }: { corpName: string }) => { }; // 1) 주말, 공휴일 여부 체크 - const today = new Date(); - const nonBusinessDay = isHoliday(today, { include: { saturday: true, sunday: true } }); // 토요일, 일요일, 공휴일 (임시 공휴일 포함) + // const today = new Date(); + // const nonBusinessDay = isHoliday(today, { include: { saturday: true, sunday: true } }); // 토요일, 일요일, 공휴일 (임시 공휴일 포함) // 🟢 2) 개장시간 여부 체크 - const currentHour = today.getHours(); - const currentMinute = today.getMinutes(); - const isBefore9AM = currentHour < 9; - const isAfter330PM = currentHour > 15 || (currentHour === 15 && currentMinute >= 30); - const closingTime = isBefore9AM || isAfter330PM; + // const currentHour = today.getHours(); + // const currentMinute = today.getMinutes(); + // const isBefore9AM = currentHour < 9; + // const isAfter330PM = currentHour > 15 || (currentHour === 15 && currentMinute >= 30); + // const closingTime = isBefore9AM || isAfter330PM; // 주문 실패 케이스 1) 개장시간 2) 가격/거래량 설정 // 🔴 3시 30분 이후 작업 위해 closingTime 조건 해제 + 주말 요건도 해제 - // const orderFailureCase01 = false; + const orderFailureCase01 = false; // 🟢 기존로직 - const orderFailureCase01 = nonBusinessDay || closingTime; + // const orderFailureCase01 = nonBusinessDay || closingTime; const orderFailureCase02 = orderPrice === 0 || orderVolume === 0; return ( diff --git a/client/src/page/MainPage.tsx b/client/src/page/MainPage.tsx index 08c1589e..93d61d77 100644 --- a/client/src/page/MainPage.tsx +++ b/client/src/page/MainPage.tsx @@ -1,6 +1,3 @@ -import { toast } from "react-toastify"; -import { setLogoutState } from "../reducer/member/loginSlice"; - import { useState, useEffect, useCallback } from "react"; import { useSelector, useDispatch } from "react-redux"; // import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; @@ -35,6 +32,8 @@ import { RootState } from "../store/config"; // 🔴 로그아웃 관련 action 함수 import { setLoginState } from "../reducer/member/loginSlice"; +import setAutoLogoutAlarm from "../utils/setAutoLogoutAlarm"; +import { secondAlarmTime, lastAlarmTime } from "../utils/setAutoLogoutAlarm"; const MainPage = () => { const expandScreen = useSelector((state: StateProps) => state.expandScreen); @@ -143,75 +142,24 @@ const MainPage = () => { if (acessToken !== null) { dispatch(setLoginState()); - // 토스트 알람 스타일 - const toastStyle = { - fontSize: "15px", - fontWeight: 350, - color: "black", - }; - - // 1) 현재시간 const currentTime = Date.now(); - const settingTime01 = 1000 * 60 * 29; // 29분 - const settingTime02 = 1000 * 60; // 1분 // 로그인 알람 설정한 시간 (세선 스토리지에 저장 되어있음) - const logoutAlarmTime01 = sessionStorage.getItem("logoutAlarmTime01"); - const logoutAlarmTime02 = sessionStorage.getItem("logoutAlarmTime02"); + const autoLogoutSecondAlarm = sessionStorage.getItem("autoLogoutSecondAlarm"); + const autoLogoutLastAlarm = sessionStorage.getItem("autoLogoutLastAlarm"); - // 2) 첫번째 알람 타이머가 아직 있다면 - if (logoutAlarmTime01 !== null) { + if (autoLogoutSecondAlarm !== null) { // 3) 비동기 설정 시간 - 새로고침 전까지 지나간 시간 - const timeGone = currentTime - parseInt(logoutAlarmTime01); - const remainTime = settingTime01 - timeGone; - - setTimeout(() => { - // 첫번째 알람 실행되었으므로 -> 첫번째 시간기록 삭제 - sessionStorage.removeItem("logoutAlarmTime01"); - - toast.warning("1분 뒤 로그아웃 처리됩니다", { - style: toastStyle, - position: "top-center", - }); - - // 2차 알람 세팅 - const logoutAlarmTime02 = Date.now(); - sessionStorage.setItem("logoutAlarmTime02", `${logoutAlarmTime02}`); - - setTimeout(() => { - // 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제 - sessionStorage.removeItem("logoutAlarmTime02"); - - dispatch(setLogoutState()); - sessionStorage.removeItem("accessToken"); - sessionStorage.removeItem("refreshToken"); - - toast.warning("로그아웃 처리되었습니다", { - style: toastStyle, - position: "top-center", - }); - }, settingTime02); - }, remainTime); + const timeGone = currentTime - parseInt(autoLogoutSecondAlarm); + const remainTime = secondAlarmTime - timeGone; + setAutoLogoutAlarm(dispatch, "second", remainTime, lastAlarmTime); } // 3) 첫번째 타이머 실행 후 -> 두번째 타이머 설정했는데 새로고침 시 - if (logoutAlarmTime02 !== null) { - const timeGone = currentTime - parseInt(logoutAlarmTime02); - const remainTime = settingTime02 - timeGone; - - setTimeout(() => { - // 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제 - sessionStorage.removeItem("logoutAlarmTime02"); - - dispatch(setLogoutState()); - sessionStorage.removeItem("accessToken"); - sessionStorage.removeItem("refreshToken"); - - toast.warning("로그아웃 처리되었습니다", { - style: toastStyle, - position: "top-center", - }); - }, remainTime); + if (autoLogoutLastAlarm !== null) { + const timeGone = currentTime - parseInt(autoLogoutLastAlarm); + const remainTime = lastAlarmTime - timeGone; + setAutoLogoutAlarm(dispatch, "last", remainTime); } } }, []); @@ -223,131 +171,36 @@ const MainPage = () => { const accessToken = urlParams.get("access_token"); const refreshToken = urlParams.get("refresh_token"); - // 🔴 자동 로그아웃 테스트 - // 현재 시간, 알림 세팅 타임, 세션 스토리지에 저장된 타이머 시간 const currentTime = Date.now(); - const settingTime01 = 1000 * 60 * 29; // 29분 - const settingTime02 = 1000 * 60; // 1분 - const logoutAlarmTime01 = sessionStorage.getItem("logoutAlarmTime01"); - const logoutAlarmTime02 = sessionStorage.getItem("logoutAlarmTime02"); - - const toastStyle = { - fontSize: "15px", - fontWeight: 350, - color: "black", - }; - - // 세션 스토리지에 저장 + 로그인 처리를 한다 + const autoLogoutSecondAlarm = sessionStorage.getItem("autoLogoutSecondAlarm"); + const autoLogoutLastAlarm = sessionStorage.getItem("autoLogoutLastAlarm"); + if (accessToken && refreshToken) { sessionStorage.setItem("accessToken", `Bearer ${accessToken}`); sessionStorage.setItem("refreshToken", refreshToken); dispatch(setLoginState()); - // // ✅ 1차 타이머도 설정되지 않았다면 -> 최초 설정 시 - if (accessToken && refreshToken && logoutAlarmTime01 === null) { - // url에 있는 파라미터를 지운다 - urlParams.delete("access_token"); - urlParams.delete("refresh_token"); - window.history.replaceState({}, "", "?" + urlParams.toString()); - - console.log("Oauth 테스트"); - - toast.warning("로그인 상태는 30분 동안 유지됩니다", { - style: toastStyle, - position: "top-center", - }); - - // 1차 타이머 저장 - const logoutAlarmTime01 = Date.now(); // 1차 알람 호출한 시간 - sessionStorage.setItem("logoutAlarmTime01", `${logoutAlarmTime01}`); // 세션 스토리지에 저장 - console.log("Oauth 테스트1"); - - setTimeout(() => { - // 첫번째 알람 실행되었으므로 -> 첫번째 시간기록 삭제 - sessionStorage.removeItem("logoutAlarmTime01"); - - toast.warning("1분 뒤 로그아웃 처리됩니다", { - style: toastStyle, - position: "top-center", - }); - - // 2차 알람 및 로그아웃 처리 + 토큰 삭제 - const logoutAlarmTime02 = Date.now(); // 2차 알람 호출한 시간 - sessionStorage.setItem("logoutAlarmTime02", `${logoutAlarmTime02}`); - - setTimeout(() => { - // 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제 - sessionStorage.removeItem("logoutAlarmTime02"); - - dispatch(setLogoutState()); - sessionStorage.removeItem("accessToken"); - sessionStorage.removeItem("refreshToken"); - - toast.warning("로그아웃 처리되었습니다", { - style: toastStyle, - position: "top-center", - }); - }, settingTime02); - }, settingTime01); - } + urlParams.delete("access_token"); + urlParams.delete("refresh_token"); + window.history.replaceState({}, "", "?" + urlParams.toString()); - // ✅ 1차 타이머는 설정 됐는데 -> 새로고침 시 - if (accessToken && refreshToken && logoutAlarmTime01 !== null) { - // 3) 비동기 설정 시간 - 새로고침 전까지 지나간 시간 - const timeGone = currentTime - parseInt(logoutAlarmTime01); - const remainTime = settingTime01 - timeGone; - - setTimeout(() => { - // 첫번째 알람 실행되었으므로 -> 첫번째 시간기록 삭제 - sessionStorage.removeItem("logoutAlarmTime01"); - - toast.warning("1분 뒤 로그아웃 처리됩니다", { - style: toastStyle, - position: "top-center", - }); - - // 2차 알람설정 - const logoutAlarmTime02 = Date.now(); - sessionStorage.setItem("logoutAlarmTime02", `${logoutAlarmTime02}`); - - setTimeout(() => { - // 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제 - sessionStorage.removeItem("logoutAlarmTime02"); - - dispatch(setLogoutState()); - sessionStorage.removeItem("accessToken"); - sessionStorage.removeItem("refreshToken"); - - toast.warning("로그아웃 처리되었습니다", { - style: toastStyle, - position: "top-center", - }); - }, settingTime02); - }, remainTime); + if (autoLogoutSecondAlarm === null) { + setAutoLogoutAlarm(dispatch, "first", secondAlarmTime, lastAlarmTime); } - // ✅ 두번째 타이머 설정 됐는데 -> 새로고침 시 - if (accessToken && refreshToken && logoutAlarmTime02 !== null) { - const timeGone = currentTime - parseInt(logoutAlarmTime02); - const remainTime = settingTime02 - timeGone; - - setTimeout(() => { - // 두번째 알람 실행되었으므로 -> 두번째 시간기록 삭제 - sessionStorage.removeItem("logoutAlarmTime02"); - - dispatch(setLogoutState()); - sessionStorage.removeItem("accessToken"); - sessionStorage.removeItem("refreshToken"); + if (autoLogoutSecondAlarm !== null) { + const timeGone = currentTime - parseInt(autoLogoutSecondAlarm); + const remainTime = secondAlarmTime - timeGone; + setAutoLogoutAlarm(dispatch, "second", remainTime, lastAlarmTime); + } - toast.warning("로그아웃 처리되었습니다", { - style: toastStyle, - position: "top-center", - }); - }, remainTime); + if (autoLogoutLastAlarm !== null) { + const timeGone = currentTime - parseInt(autoLogoutLastAlarm); + const remainTime = lastAlarmTime - timeGone; + setAutoLogoutAlarm(dispatch, "last", remainTime); } } }, []); - // 🔴 자동 로그아웃 관련 코드 -> 정리 필요 const [isGuideModalOpen, setGuideModalOpen] = useState(false); diff --git a/client/src/utils/README.md b/client/src/utils/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/client/src/utils/setAutoLogoutAlarm.ts b/client/src/utils/setAutoLogoutAlarm.ts new file mode 100644 index 00000000..57892184 --- /dev/null +++ b/client/src/utils/setAutoLogoutAlarm.ts @@ -0,0 +1,120 @@ +import { toast } from "react-toastify"; +import { setLogoutState } from "../reducer/member/loginSlice"; + +/* +- 자동 로그아웃 설정을 하는 Custom Hook입니다. + +- 총 3차례의 토스트 메시지 안내를 실행합니다 + 1차) 로그인 시 30분 뒤 로그아웃 됨을 알림 + 2차) 로그아웃 시간 1분 남음을 알림 + 3차) 로그아웃 처리 되었음을 알림 + +- 해당 hook은 총 4개의 인자를 가집니다 + 1) 로그인 전역상태 변경에 필요한 dispatch + 2) 알람 설정 개수 (first일 경우 3개 다, second일 경우 2개, last일 경우 마지막 1개만 설정) + 3) 1차 알림 설정 시간 (설정한 시간만큼 지난 후 1차 알림 발생) + 4) 2차 알림 설정 시간 (상동) +*/ + +export const secondAlarmTime = 1000 * 60 * 29; // 29분 +export const lastAlarmTime = 1000 * 60; // 1분 + +const setAutoLogoutAlarm = (dispatch: any, alarmNum: "first" | "second" | "last", secondAlarmTime: number, lastAlarmTime?: number) => { + // 1~3차 알림 모두 설정 + if (alarmNum === "first") { + toast.warning("로그인 상태는 30분 동안 유지됩니다", { + style: toastStyle, + position: "top-center", + }); + + // 2차 알림 셋팅 시간 기록 + const autoLogoutSecondAlarm = Date.now(); + sessionStorage.setItem("autoLogoutSecondAlarm", `${autoLogoutSecondAlarm}`); + + setTimeout(() => { + // 2차 알림 셋팅 시간 제거 + sessionStorage.removeItem("autoLogoutSecondAlarm"); + + toast.warning("1분 뒤 로그아웃 처리됩니다", { + style: toastStyle, + position: "top-center", + }); + + // 3차 알림 셋팅 시간 기록 + const autoLogoutLastAlarm = Date.now(); + sessionStorage.setItem("autoLogoutLastAlarm", `${autoLogoutLastAlarm}`); + + setTimeout(() => { + // 3차 알림 셋팅 시간 제거 + sessionStorage.removeItem("autoLogoutLastAlarm"); + + dispatch(setLogoutState()); + sessionStorage.removeItem("accessToken"); + sessionStorage.removeItem("refreshToken"); + + toast.warning("로그아웃 처리되었습니다", { + style: toastStyle, + position: "top-center", + }); + }, lastAlarmTime); + }, secondAlarmTime); + } + + // 2~3차 알림 설정 + if (alarmNum === "second") { + setTimeout(() => { + // 2차 알림 셋팅 시간 제거 + sessionStorage.removeItem("autoLogoutSecondAlarm"); + + toast.warning("1분 뒤 로그아웃 처리됩니다", { + style: toastStyle, + position: "top-center", + }); + + // 3차 알림 셋팅 시간 기록 + const autoLogoutLastAlarm = Date.now(); + sessionStorage.setItem("autoLogoutLastAlarm", `${autoLogoutLastAlarm}`); + + setTimeout(() => { + // 3차 알림 셋팅 시간 제거 + sessionStorage.removeItem("autoLogoutLastAlarm"); + + dispatch(setLogoutState()); + sessionStorage.removeItem("accessToken"); + sessionStorage.removeItem("refreshToken"); + + toast.warning("로그아웃 처리되었습니다", { + style: toastStyle, + position: "top-center", + }); + }, lastAlarmTime); + }, secondAlarmTime); + + return; + } + + // 3차 알림만 설정 + if (alarmNum === "last") { + setTimeout(() => { + // 3차 알림 셋팅 시간 제거 + sessionStorage.removeItem("autoLogoutLastAlarm"); + + dispatch(setLogoutState()); + sessionStorage.removeItem("accessToken"); + sessionStorage.removeItem("refreshToken"); + + toast.warning("로그아웃 처리되었습니다", { + style: toastStyle, + position: "top-center", + }); + }, lastAlarmTime); + } +}; + +export default setAutoLogoutAlarm; + +const toastStyle = { + fontSize: "15px", + fontWeight: 350, + color: "black", +};