diff --git a/src/components/CourseRegister/StartButton.tsx b/src/components/CourseRegister/StartButton.tsx index 2b82a09..931a44a 100644 --- a/src/components/CourseRegister/StartButton.tsx +++ b/src/components/CourseRegister/StartButton.tsx @@ -1,42 +1,155 @@ +import {useEffect, useState} from 'react'; import styled from 'styled-components'; +import {useDispatch} from 'react-redux'; import {deleteAllRegistrations} from '@apis/api/course.ts'; +import {setEndCount, setTime} from '@/store/modules/courseRegisteredSlice'; +import {FilterWrap} from '@/styles/FilterLayout'; +import {useAppSelector} from '@/store/hooks'; interface StartBtnProps { onClick: () => void; } function StartButton({onClick}: StartBtnProps) { + const dispatch = useDispatch(); + const time = useAppSelector(state => state.courseRegistered.time); + const [timeout, setTimeout] = useState(time); + const [timeLeft, setTimeLeft] = useState(35); + const [isRunning, setIsRunning] = useState(false); + useEffect(() => { + if (!isRunning || timeLeft <= 0) return; + + const countdown = setInterval(() => { + setTimeLeft(prev => prev - 1); + }, 1000); + + return () => clearInterval(countdown); + }, [isRunning, timeLeft]); + + useEffect(() => { + if (timeLeft === 0) { + setIsRunning(false); + setTimeLeft(time); + dispatch(setEndCount(true)); + console.log('제한 시간 초과'); + } + }, [timeLeft, dispatch]); + const handleClick = async () => { if (!confirm('수강신청 연습 시작하시겠습니까?')) return; + //카운트다운 중에 재시작 + if (isRunning) { + setTimeLeft(time); + } + + setIsRunning(true); await deleteAllRegistrations(); onClick(); }; + const handleInput = (e: React.ChangeEvent) => { + const timeInput = parseInt(e.target.value); + + if (e.target.value) { + setTimeout(timeInput); + setTimeLeft(timeInput); + dispatch(setTime(timeInput)); + } else { + setTimeout(''); + setTimeLeft(35); + dispatch(setTime(35)); + } + }; + + const formatTime = (time: number) => { + return time.toString().padStart(2, '0'); + }; + return ( -

시작 버튼을 누르면 수강 신청이 시작됩니다. 다시 연습하고 싶다면 한번 더 버튼을 눌러주세요.

-

시작 후, 35초가 지나면 모든 과목이 수강여석 없음으로 변경됩니다.

+

+ 시작 버튼을 누르면 수강 신청이 시작됩니다. 다시 연습하고 싶다면 한번 더 + 버튼을 눌러주세요. +

현재 상태를 확인하고 싶다면, 재조회 버튼을 눌러주세요.

- 시작 / 초기화 +
    +

    제한 시간 안내

    +
  • 기본 설정: 35초
  • +
  • 최소 시간: 10초 (10초 이하 입력 시 자동으로 10초로 조정)
  • +
  • + 최대 시간: 1시간(3600초) (1시간 이상 입력 시 자동으로 1시간으로 조정) +
  • +
  • + 설정한 제한 시간이 지나면 모든 과목의 수강여석이 없음으로 변경됩니다. +
  • +
    ※ 초단위로 입력해주세요!
    +
+ + {formatTime(Math.floor(timeLeft / 60))}: + {formatTime(timeLeft % 60)} + + + 제한 시간 + + 시작 / 초기화 +
); } const Container = styled.div` + font-weight: normal; + > p { + font-size: 1.6rem; + margin-bottom: 1.5rem; + } + > ul { + font-size: 1.6rem; + margin-bottom: 1rem; + > p { - font-weight: normal; - font-size: 1.6rem; - margin-bottom: 15px; + font-weight: bold; + margin-bottom: 1rem; + } + > li { + list-style-type: square; + margin: 0 0 0.7rem 2rem; + } + > h5 { + color: ${props => props.theme.colors.primary}; + font-weight: bold; } + } +`; + +const InputWrap = styled(FilterWrap)` + margin: 1.5rem 0; `; + +const InputBox = styled.input` + height: 2.4rem; + border: 1px solid ${props => props.theme.colors.neutral4}; + padding-left: 0.5rem; + width: 21.5rem; +`; + +const TimerWrap = styled.div<{$isAlmostDone: boolean}>` + ${props => props.theme.texts.title}; + margin: 1.5rem 0; + font-size: 2.5rem; + letter-spacing: 0.5rem; + color: ${props => + props.$isAlmostDone ? props.theme.colors.primary : 'inherit'}; +`; + const ButtonWrap = styled.button` ${props => props.theme.texts.content}; background-color: ${props => props.theme.colors.primary}; color: ${props => props.theme.colors.white}; width: 8rem; height: 2.4rem; - margin-bottom: 10px; + margin-left: 1rem; &:hover { filter: grayscale(15%); diff --git a/src/components/CourseRegister/index.tsx b/src/components/CourseRegister/index.tsx index 8414842..1cb7776 100644 --- a/src/components/CourseRegister/index.tsx +++ b/src/components/CourseRegister/index.tsx @@ -52,7 +52,7 @@ function CourseRegister() { useEffect(() => { dispatch(setEndCount(false)); - }, []); + }, [dispatch]); const refreshAll = useCallback(async () => { const registeredCourses = await getRegisterdList(); @@ -89,11 +89,6 @@ function CourseRegister() { setIsRegistrationStarted(true); setIsFirstSearch(true); dispatch(setEndCount(false)); - - setTimeout(() => { - console.log('35초 지남'); - dispatch(setEndCount(true)); - }, 35000); }; const handleAction = async ( diff --git a/src/components/Header/TopMenu.tsx b/src/components/Header/TopMenu.tsx index f230491..480919f 100644 --- a/src/components/Header/TopMenu.tsx +++ b/src/components/Header/TopMenu.tsx @@ -7,6 +7,7 @@ import {useAppSelector} from '@/store/hooks'; import {clearUserInfo} from '@/store/modules/userSlice'; import logout from '@assets/img/logout.png'; import Clock from './Clock'; +import {resetCourseRegistered} from '@/store/modules/courseRegisteredSlice'; function TopMenu() { const navigate = useNavigate(); @@ -15,6 +16,7 @@ function TopMenu() { const handleLogout = () => { dispatch(clearUserInfo()); + dispatch(resetCourseRegistered()); delete baseAPI.defaults.headers.common['Authorization']; Cookies.remove('accessToken'); navigate('/login'); diff --git a/src/store/modules/courseRegisteredSlice.ts b/src/store/modules/courseRegisteredSlice.ts index 86694df..4769494 100644 --- a/src/store/modules/courseRegisteredSlice.ts +++ b/src/store/modules/courseRegisteredSlice.ts @@ -1,25 +1,48 @@ import {createSlice} from '@reduxjs/toolkit'; export interface CourseRegistered { - endCount: boolean + endCount: boolean; + time: number; } const courseRegistered = createSlice({ name: 'courseRegistered', initialState: { endCount: false, + time: 35, }, reducers: { setEndCount(state: CourseRegistered, {payload}: {payload: boolean}) { state.endCount = payload; }, - + setTime(state: CourseRegistered, {payload}: {payload: number}) { + if (payload <= 10) { + state.time = 10; + } else if (payload >= 3600) { + state.time = 3600; + } else { + state.time = payload; + } + }, clearCount(state: CourseRegistered) { state.endCount = false; }, + cleatTime(state: CourseRegistered) { + state.time = 35; + }, + resetCourseRegistered(state: CourseRegistered) { + state.endCount = false; + state.time = 35; + }, }, }); -export const {setEndCount, clearCount} = courseRegistered.actions; +export const { + setEndCount, + setTime, + clearCount, + cleatTime, + resetCourseRegistered, +} = courseRegistered.actions; -export default courseRegistered.reducer; \ No newline at end of file +export default courseRegistered.reducer;