From 8925c7fd4b3610683c9258930df5acadec831612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Wed, 14 Aug 2024 19:50:45 +0900 Subject: [PATCH 01/24] =?UTF-8?q?fix:=20invalidateQueries=EC=97=90=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=ED=91=9C=20=EC=82=AD=EC=A0=9C=ED=95=A0?= =?UTF-8?q?=EB=95=8C=20userName=20=ED=95=A0=EB=8B=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/molecules/ScriptToolTip/ScriptToolTip.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/molecules/ScriptToolTip/ScriptToolTip.tsx b/src/components/molecules/ScriptToolTip/ScriptToolTip.tsx index a4e4624..d2330e4 100644 --- a/src/components/molecules/ScriptToolTip/ScriptToolTip.tsx +++ b/src/components/molecules/ScriptToolTip/ScriptToolTip.tsx @@ -29,7 +29,9 @@ const ScriptToolTip = ({ id, scheduleName }: IProps) => { const deleteMutation = useMutation({ mutationFn: (id: number) => deleteScheduleElement(id, userInfo.userName), onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['schedule', name] }); + queryClient.invalidateQueries({ + queryKey: ['schedule', userInfo.userName], + }); }, onError: () => { alert('시간표 삭제를 실패했습니다.'); From 488e8ecd71a064a5979edf7990f0d095a1037ea5 Mon Sep 17 00:00:00 2001 From: Bella Date: Thu, 15 Aug 2024 04:23:53 +0900 Subject: [PATCH 02/24] =?UTF-8?q?feat:=20=EC=B9=B4=EC=B9=B4=EC=98=A4=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/auth.ts | 11 ++++++++--- src/pages/Auth/AuthForm/AuthForm.tsx | 16 +++++++++++----- src/pages/Auth/OAuthCallback.tsx | 11 +++++++---- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/apis/auth.ts b/src/apis/auth.ts index a9e9ef9..e04d48d 100644 --- a/src/apis/auth.ts +++ b/src/apis/auth.ts @@ -11,7 +11,8 @@ interface IEmailLoginParams { userPassword: string; } -interface IGoogleLoginParams { +interface ISocialLoginParams { + social: string; state: string; code: string; } @@ -35,10 +36,14 @@ interface ITokens { refreshToken: string; } -export const googleLogin = async ({ state, code }: IGoogleLoginParams) => { +export const OAuthLogin = async ({ + social, + state, + code, +}: ISocialLoginParams) => { try { const res = await fetch( - `${API_URL}/login/oauth2/code/google?state=${state}&code=${code}`, + `${API_URL}/login/oauth2/code/${social}?state=${state}&code=${code}`, { credentials: 'include', }, diff --git a/src/pages/Auth/AuthForm/AuthForm.tsx b/src/pages/Auth/AuthForm/AuthForm.tsx index 078d857..268ab9b 100644 --- a/src/pages/Auth/AuthForm/AuthForm.tsx +++ b/src/pages/Auth/AuthForm/AuthForm.tsx @@ -44,7 +44,6 @@ const AuthForm = ({ e.preventDefault(); setIsShowPasswordConfirmClick((prev) => !prev); }; - const loginMutation = useMutation({ mutationFn: emailLogin, onSuccess: (data) => { @@ -93,8 +92,8 @@ const AuthForm = ({ } }; - const handleGoogleClick = () => { - window.location.href = `${API_URL}/oauth2/authorization/google`; + const handleOAuthClick = (e: string) => { + window.location.href = `${API_URL}/oauth2/authorization/${e}`; }; return ( @@ -178,11 +177,18 @@ const AuthForm = ({
-
diff --git a/src/pages/Auth/OAuthCallback.tsx b/src/pages/Auth/OAuthCallback.tsx index 60ea1a8..af5bc7f 100644 --- a/src/pages/Auth/OAuthCallback.tsx +++ b/src/pages/Auth/OAuthCallback.tsx @@ -1,19 +1,22 @@ import { useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useLocation } from 'react-router-dom'; import { useQuery } from '@tanstack/react-query'; -import { googleLogin } from '../../apis/auth'; +import { OAuthLogin } from '../../apis/auth'; import Loading from '../../assets/images/LoadingCircle.gif'; import styles from './OAuthCallback.module.scss'; const OAuthCallback = () => { const navigate = useNavigate(); const searchParams = new URLSearchParams(window.location.search); + const params = useLocation(); + const parts = params.pathname?.split('/'); + const social = parts[1]; const state = searchParams.get('state') || ''; const code = searchParams.get('code') || ''; const { data, isError } = useQuery({ - queryKey: ['google', code], - queryFn: () => googleLogin({ state, code }), + queryKey: ['oauth', code], + queryFn: () => OAuthLogin({ social, state, code }), enabled: !!state && !!code, retry: false, }); From 66e185466f385b8f0da5a6a60186ee45b95aeb9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Fri, 16 Aug 2024 19:36:22 +0900 Subject: [PATCH 03/24] =?UTF-8?q?chore:=20meta=20description=EC=97=90=20?= =?UTF-8?q?=EC=82=AC=EC=9D=B4=ED=8A=B8=20=EC=84=A4=EB=AA=85=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/index.html b/index.html index a2cb802..63ea31b 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,7 @@ + Hearus From 2efb9d02b1e90fc74e7e6577898f9fb767ddc776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Fri, 16 Aug 2024 19:36:52 +0900 Subject: [PATCH 04/24] =?UTF-8?q?fix:=20=EC=9C=A0=EC=A0=80=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=ED=8F=BC=EC=97=90=EC=84=9C=20=EC=97=94=ED=84=B0?= =?UTF-8?q?=EB=88=84=EB=A5=B4=EB=A9=B4=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=ED=91=9C=EC=8B=9C=20=EB=B2=84=ED=8A=BC=EC=9D=B4=20?= =?UTF-8?q?=EC=9E=91=EB=8F=99=ED=95=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Auth/AuthForm/AuthForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Auth/AuthForm/AuthForm.tsx b/src/pages/Auth/AuthForm/AuthForm.tsx index 268ab9b..f680f5f 100644 --- a/src/pages/Auth/AuthForm/AuthForm.tsx +++ b/src/pages/Auth/AuthForm/AuthForm.tsx @@ -123,9 +123,9 @@ const AuthForm = ({ value={password} onChange={(e) => setPassword(e.target.value)} /> - +
{title === '로그인' && (
From ac80ee3a8052e9b78d2b01d20b6fe590ed45422b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Fri, 16 Aug 2024 19:52:58 +0900 Subject: [PATCH 05/24] =?UTF-8?q?refactor:=20=EB=B3=80=EC=88=98=EB=AA=85?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20import=EB=AC=B8=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AddScheduleForm/AddScheduleForm.tsx | 8 +++--- src/constants/schedule.ts | 21 ++++++++++++++- src/utils/schedule.ts | 27 +++---------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/components/organisms/AddScheduleForm/AddScheduleForm.tsx b/src/components/organisms/AddScheduleForm/AddScheduleForm.tsx index 4aafc3a..2a801ac 100644 --- a/src/components/organisms/AddScheduleForm/AddScheduleForm.tsx +++ b/src/components/organisms/AddScheduleForm/AddScheduleForm.tsx @@ -1,8 +1,11 @@ import React, { useState, useEffect, useRef } from 'react'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { useUserInfoStore } from '../../../store/userUserInfoStore'; import Warning from '../../../assets/images/warning.svg?react'; import { COLORS, ColorKey, + IScheduleElementDTO, LectureInfo, daysOfWeek, initialLectureInfo, @@ -10,13 +13,10 @@ import { import { getIsAddScheduleFormValid, getIsTimeValid, - IScheduleElementDTO, transformToScheduleElementDTO, } from '../../../utils/schedule'; -import styles from './AddScheduleForm.module.scss'; -import { useMutation, useQueryClient } from '@tanstack/react-query'; import { addScheduleElement } from '../../../apis/schedule'; -import { useUserInfoStore } from '../../../store/userUserInfoStore'; +import styles from './AddScheduleForm.module.scss'; interface IProps { onClose: () => void; diff --git a/src/constants/schedule.ts b/src/constants/schedule.ts index 72fb4d5..3b51f86 100644 --- a/src/constants/schedule.ts +++ b/src/constants/schedule.ts @@ -13,6 +13,15 @@ export interface IScheduleElement { endTime: string; } +export interface IScheduleElementDTO { + name: string; + location: string; + dayOfWeek: string; + startTime: string; + endTime: string; + color: ColorKey; +} + export const TIMELIST = Array.from(Array(13), (_, i) => i + 9); export const COLORS = { @@ -49,7 +58,7 @@ export const initialLectureInfo: LectureInfo = { endMinute: '00', }; -export const daysObject = { +export const daysKorEnMap = { 월: 'MON', 화: 'TUE', 수: 'WED', @@ -58,3 +67,13 @@ export const daysObject = { 토: 'SAT', 일: 'SUN', }; + +export const daysEnNumMap: Record = { + SUN: 0, + MON: 1, + TUE: 2, + WED: 3, + THU: 4, + FRI: 5, + SAT: 6, +}; diff --git a/src/utils/schedule.ts b/src/utils/schedule.ts index f2876d3..562249f 100644 --- a/src/utils/schedule.ts +++ b/src/utils/schedule.ts @@ -1,20 +1,10 @@ import { - ColorKey, + daysEnNumMap, DayOfWeek, - daysObject, + daysKorEnMap, LectureInfo, } from '../constants/schedule'; -const DAYMAP: Record = { - SUN: 0, - MON: 1, - TUE: 2, - WED: 3, - THU: 4, - FRI: 5, - SAT: 6, -}; - export const getScheduleStyle = ( dayOfWeek: DayOfWeek, startTime: string, @@ -27,7 +17,7 @@ export const getScheduleStyle = ( // return 값 const top = (startHour + startMinute - 9) * 80 + 60; const height = (endHour + endMinute - startHour - startMinute) * 80; - const left = `calc((100% - 120px) * ${DAYMAP[dayOfWeek]} / 7)`; + const left = `calc((100% - 120px) * ${daysEnNumMap[dayOfWeek]} / 7)`; return { '--schedule-left': left, @@ -91,7 +81,7 @@ export const getIsAddScheduleFormValid = ({ // 요일 한글 -> 대문자 영어 변환 const getDayOfWeek = (day: string) => { - return daysObject[day as keyof typeof daysObject] || day; + return daysKorEnMap[day as keyof typeof daysKorEnMap] || day; }; // 시간 ISO 변환 @@ -103,15 +93,6 @@ const getFormattedTime = (hour: string, minute: string) => { return `${dateString}T${timeString}`; }; -export interface IScheduleElementDTO { - name: string; - location: string; - dayOfWeek: string; - startTime: string; - endTime: string; - color: ColorKey; -} - export const transformToScheduleElementDTO = (lectureData: LectureInfo) => { const transformedData = { name: lectureData.title, From 643c6b78315f59b4da189947abccbdcbef28846a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Fri, 16 Aug 2024 20:32:50 +0900 Subject: [PATCH 06/24] =?UTF-8?q?feat:=20=EC=8B=9C=EA=B0=84=20=EC=B6=A9?= =?UTF-8?q?=EB=8F=8C=20=ED=99=95=EC=9D=B8=20=ED=95=A8=EC=88=98=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/schedule.ts | 2 +- .../AddScheduleForm/AddScheduleForm.tsx | 22 ++++++++++++++- src/constants/schedule.ts | 13 +++++++-- src/utils/schedule.ts | 28 +++++++++++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/apis/schedule.ts b/src/apis/schedule.ts index 5d13fa0..2d13907 100644 --- a/src/apis/schedule.ts +++ b/src/apis/schedule.ts @@ -1,6 +1,6 @@ import { API_URL } from '.'; import { IScheduleElement } from '../constants/schedule'; -import { IScheduleElementDTO } from '../utils/schedule'; +import { IScheduleElementDTO } from '../constants/schedule'; import { getToken } from './'; interface IGetScheduleResponse { diff --git a/src/components/organisms/AddScheduleForm/AddScheduleForm.tsx b/src/components/organisms/AddScheduleForm/AddScheduleForm.tsx index 2a801ac..29c9953 100644 --- a/src/components/organisms/AddScheduleForm/AddScheduleForm.tsx +++ b/src/components/organisms/AddScheduleForm/AddScheduleForm.tsx @@ -5,6 +5,7 @@ import Warning from '../../../assets/images/warning.svg?react'; import { COLORS, ColorKey, + IScheduleElement, IScheduleElementDTO, LectureInfo, daysOfWeek, @@ -13,6 +14,7 @@ import { import { getIsAddScheduleFormValid, getIsTimeValid, + hasNewElementConflict, transformToScheduleElementDTO, } from '../../../utils/schedule'; import { addScheduleElement } from '../../../apis/schedule'; @@ -98,6 +100,7 @@ const AddScheduleForm = ({ onClose }: IProps) => { mutationFn: (data: IScheduleElementDTO) => addScheduleElement(data, userInfo.userName), onSuccess: () => { + alert('강의 추가에 성공했습니다.'); onClose(); queryClient.invalidateQueries({ queryKey: ['schedule', userInfo.userName], @@ -110,8 +113,25 @@ const AddScheduleForm = ({ onClose }: IProps) => { const handleSubmit = () => { if (isFormValid) { + const existingSchedule = queryClient.getQueryData([ + 'schedule', + userInfo.userName, + ]); const formattedData = transformToScheduleElementDTO(lectureInfo); - postMutation.mutate(formattedData); + if (existingSchedule) { + if (hasNewElementConflict(formattedData, existingSchedule)) { + alert( + '새로운 강의 시간이 기존 스케줄과 겹칩니다. 다른 시간을 선택해주세요.', + ); + return; + } else { + postMutation.mutate(formattedData); + } + } else { + alert( + '스케줄 데이터를 불러올 수 없습니다. 페이지를 새로고침한 후 다시 시도해주세요.', + ); + } } }; diff --git a/src/constants/schedule.ts b/src/constants/schedule.ts index 3b51f86..79cfe44 100644 --- a/src/constants/schedule.ts +++ b/src/constants/schedule.ts @@ -13,10 +13,19 @@ export interface IScheduleElement { endTime: string; } +export interface IAddScheduleElement { + name: string; + location: string; + dayOfWeek: DayOfWeek; + color: ColorKey; + startTime: string; + endTime: string; +} + export interface IScheduleElementDTO { name: string; location: string; - dayOfWeek: string; + dayOfWeek: DayOfWeek; startTime: string; endTime: string; color: ColorKey; @@ -66,7 +75,7 @@ export const daysKorEnMap = { 금: 'FRI', 토: 'SAT', 일: 'SUN', -}; +} as const; export const daysEnNumMap: Record = { SUN: 0, diff --git a/src/utils/schedule.ts b/src/utils/schedule.ts index 562249f..8d7f8ff 100644 --- a/src/utils/schedule.ts +++ b/src/utils/schedule.ts @@ -3,6 +3,8 @@ import { DayOfWeek, daysKorEnMap, LectureInfo, + IScheduleElement, + IAddScheduleElement, } from '../constants/schedule'; export const getScheduleStyle = ( @@ -104,3 +106,29 @@ export const transformToScheduleElementDTO = (lectureData: LectureInfo) => { }; return transformedData; }; + +export const hasNewElementConflict = ( + newElement: IAddScheduleElement, + existingElements: IScheduleElement[], +): boolean => { + for (const existingElement of existingElements) { + if (newElement.dayOfWeek === existingElement.dayOfWeek) { + const startNew = new Date(`1970-01-01T${newElement.startTime}`).getTime(); + const endNew = new Date(`1970-01-01T${newElement.endTime}`).getTime(); + const startExisting = new Date( + `1970-01-01T${existingElement.startTime}`, + ).getTime(); + const endExisting = new Date( + `1970-01-01T${existingElement.endTime}`, + ).getTime(); + + if ( + (startNew < endExisting && startExisting < endNew) || + (startExisting < endNew && startNew < endExisting) + ) { + return true; + } + } + } + return false; +}; From ba2392fc3f66173c6db6becbe9b94c5ee468dcde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Fri, 16 Aug 2024 21:29:11 +0900 Subject: [PATCH 07/24] =?UTF-8?q?refactor:=20=EC=95=88=EC=93=B0=EB=8A=94?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useModal.ts | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 src/hooks/useModal.ts diff --git a/src/hooks/useModal.ts b/src/hooks/useModal.ts deleted file mode 100644 index 6681a13..0000000 --- a/src/hooks/useModal.ts +++ /dev/null @@ -1,30 +0,0 @@ -// type OpenModalType = { -// title: string; -// content: JSX.Element | string; -// callback?: () => any; -// }; - -// export const useModal = () => { -// const [modalDataState, setModalDataState] = useRecoilState(modalState); - -// const closeModal = useCallback( -// () => -// setModalDataState((prev) => { -// return { ...prev, isOpen: false }; -// }), -// [setModalDataState] -// ); - -// const openModal = useCallback( -// ({ title, content, callback }: OpenModalType) => -// setModalDataState({ -// isOpen: true, -// title: title, -// content: content, -// callBack: callback -// }), -// [setModalDataState] -// ); - -// return { modalDataState, closeModal, openModal }; -// }; From 01ac2702fc5dd3fa30684768c022365de7ec5652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sat, 17 Aug 2024 13:28:00 +0900 Subject: [PATCH 08/24] =?UTF-8?q?fix:=20=EC=A4=91=EB=B3=B5=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=ED=91=9C=20=EA=B2=80=EC=82=AC=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/schedule.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/utils/schedule.ts b/src/utils/schedule.ts index 8d7f8ff..199da9d 100644 --- a/src/utils/schedule.ts +++ b/src/utils/schedule.ts @@ -113,13 +113,17 @@ export const hasNewElementConflict = ( ): boolean => { for (const existingElement of existingElements) { if (newElement.dayOfWeek === existingElement.dayOfWeek) { - const startNew = new Date(`1970-01-01T${newElement.startTime}`).getTime(); - const endNew = new Date(`1970-01-01T${newElement.endTime}`).getTime(); + const startNew = new Date( + `1970-01-01T${newElement.startTime.slice(11)}`, + ).getTime(); + const endNew = new Date( + `1970-01-01T${newElement.endTime.slice(11)}`, + ).getTime(); const startExisting = new Date( - `1970-01-01T${existingElement.startTime}`, + `1970-01-01T${existingElement.startTime.slice(11)}`, ).getTime(); const endExisting = new Date( - `1970-01-01T${existingElement.endTime}`, + `1970-01-01T${existingElement.endTime.slice(11)}`, ).getTime(); if ( From 7992dbac203134021f1c2397ed8a3bc4bd49ca76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sat, 17 Aug 2024 13:54:52 +0900 Subject: [PATCH 09/24] =?UTF-8?q?refacotr:=20Response=20=EA=B3=B5=ED=86=B5?= =?UTF-8?q?=20interface=20=EB=A7=8C=EB=93=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/auth.ts | 22 +++------------------- src/apis/index.ts | 9 +++++++++ src/apis/record.ts | 3 --- src/apis/schedule.ts | 39 +++++++++++++-------------------------- src/apis/script.ts | 16 +++------------- src/apis/test.ts | 9 ++------- src/apis/user.ts | 9 ++------- src/hooks/useSocket.ts | 2 +- 8 files changed, 33 insertions(+), 76 deletions(-) delete mode 100644 src/apis/record.ts diff --git a/src/apis/auth.ts b/src/apis/auth.ts index e04d48d..a7d16b8 100644 --- a/src/apis/auth.ts +++ b/src/apis/auth.ts @@ -1,4 +1,4 @@ -import { API_URL } from '.'; +import { API_URL, IApiResponse } from '.'; interface IEmailSignUpParams { userEmail: string; @@ -17,18 +17,9 @@ interface ISocialLoginParams { code: string; } -interface ILoginResponse { - status: string; - msg: string; - object: ITokens; -} +interface ILoginResponse extends IApiResponse {} -interface IEmailSignupResponse { - status: string; - msg: string; - object: null; - success: boolean; -} +interface IEmailSignupResponse extends IApiResponse {} interface ITokens { grantType: string; @@ -71,9 +62,6 @@ export const emailLogin = async ({ userIsOAuth: false, }), }); - if (!res.ok) { - throw new Error('Login failed'); - } const data: ILoginResponse = await res.json(); return data.object; } catch (error) { @@ -100,10 +88,6 @@ export const emailSignUp = async ({ }), }); const data: IEmailSignupResponse = await res.json(); - - if (!res.ok) { - throw new Error('SignUp failed'); - } return data; } catch (error) { throw error; diff --git a/src/apis/index.ts b/src/apis/index.ts index b40063a..d308b8e 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -1,6 +1,15 @@ export const API_URL: string = import.meta.env.VITE_API_URL; +export const SOCKETURL = import.meta.env.VITE_SOCKETIO_HOST; + export const getToken = () => { const token = localStorage.getItem('token'); return token; }; + +export interface IApiResponse { + status: string; + msg: string; + object: T; + success: boolean; +} diff --git a/src/apis/record.ts b/src/apis/record.ts deleted file mode 100644 index 21f870e..0000000 --- a/src/apis/record.ts +++ /dev/null @@ -1,3 +0,0 @@ -const SOCKETURL = import.meta.env.VITE_SOCKETIO_HOST; - -export default SOCKETURL; diff --git a/src/apis/schedule.ts b/src/apis/schedule.ts index 2d13907..8af9afe 100644 --- a/src/apis/schedule.ts +++ b/src/apis/schedule.ts @@ -1,18 +1,14 @@ -import { API_URL } from '.'; +import { API_URL, IApiResponse, getToken } from '.'; import { IScheduleElement } from '../constants/schedule'; import { IScheduleElementDTO } from '../constants/schedule'; -import { getToken } from './'; -interface IGetScheduleResponse { - status: string; - msg: string; - object: { - id: number; - scheduleElements: IScheduleElement[]; - name: string; - userId: string | null; - }; - success: boolean; +interface IGetScheduleResponse extends IApiResponse {} + +interface IGetScheduleObject { + id: number; + scheduleElements: IScheduleElement[]; + name: string; + userId: string | null; } export const getSchedule = async ( @@ -35,12 +31,8 @@ export const getSchedule = async ( } }; -interface IGetLectureByScheduleElementResponse { - status: string; - msg: string; - object: ILectureItem[]; - success: boolean; -} +interface IGetLectureByScheduleElementResponse + extends IApiResponse {} interface ILectureItem { id: string; @@ -70,12 +62,7 @@ export const getLectureByScheduleElement = async (id: number) => { } }; -interface IPOSTScheduleElementResponse { - status: string; - msg: string; - object: null; - success: boolean; -} +interface IPOSTScheduleElementResponse extends IApiResponse {} export const addScheduleElement = async ( inputData: IScheduleElementDTO, @@ -99,7 +86,7 @@ export const addScheduleElement = async ( const data: IPOSTScheduleElementResponse = await res.json(); return data.success; } catch (error) { - throw new Error('Failed to delete schedule element'); + throw error; } }; @@ -127,6 +114,6 @@ export const deleteScheduleElement = async ( const data: IPOSTScheduleElementResponse = await res.json(); return data.success; } catch (error) { - throw new Error('Failed to delete schedule element'); + throw error; } }; diff --git a/src/apis/script.ts b/src/apis/script.ts index 830e310..0ffb7a3 100644 --- a/src/apis/script.ts +++ b/src/apis/script.ts @@ -1,18 +1,8 @@ -import { API_URL, getToken } from '.'; +import { API_URL, getToken, IApiResponse } from '.'; -interface IGetAllScriptResponse { - status: string; - msg: string; - object: IScriptInList[]; - success: boolean; -} +interface IGetAllScriptResponse extends IApiResponse {} -interface IGetScriptDetailResponse { - status: string; - msg: string; - object: IScriptDetail; - success: boolean; -} +interface IGetScriptDetailResponse extends IApiResponse {} export interface IScriptInList { id: string; diff --git a/src/apis/test.ts b/src/apis/test.ts index 2c48efe..514cf15 100644 --- a/src/apis/test.ts +++ b/src/apis/test.ts @@ -1,11 +1,6 @@ -import { API_URL, getToken } from '.'; +import { API_URL, getToken, IApiResponse } from '.'; -interface IGenerateProblemResponse { - status: string; - msg: string; - object: IQuestion[]; - success: boolean; -} +interface IGenerateProblemResponse extends IApiResponse {} export interface IQuestion { type: string; diff --git a/src/apis/user.ts b/src/apis/user.ts index 7a099ce..9ef6ecf 100644 --- a/src/apis/user.ts +++ b/src/apis/user.ts @@ -1,11 +1,6 @@ -import { API_URL, getToken } from '.'; +import { API_URL, getToken, IApiResponse } from '.'; -interface IGetUserInfoResponse { - status: string; - msg: string; - object: IUserInfo; - success: boolean; -} +interface IGetUserInfoResponse extends IApiResponse {} export interface IUserInfo { userId: string; diff --git a/src/hooks/useSocket.ts b/src/hooks/useSocket.ts index d13d02a..6830e65 100644 --- a/src/hooks/useSocket.ts +++ b/src/hooks/useSocket.ts @@ -1,6 +1,6 @@ import { useEffect, useRef } from 'react'; import { io, Socket } from 'socket.io-client'; -import SOCKETURL from '../apis/record'; +import { SOCKETURL } from '../apis/index'; export const useSocket = (onTransitionResult: (result: string) => void) => { const socketRef = useRef(null); From a22c02d7965f595ae9a5f206ef59a90ea860701a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sat, 17 Aug 2024 15:18:18 +0900 Subject: [PATCH 10/24] =?UTF-8?q?feat:=20username=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=90=9C=20schedule=20=EC=97=86=EC=9D=84=20=EC=8B=9C=20usernam?= =?UTF-8?q?e=EC=9C=BC=EB=A1=9C=20schedue=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/index.ts | 2 ++ src/apis/schedule.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/apis/index.ts b/src/apis/index.ts index d308b8e..5e5a06e 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -1,7 +1,9 @@ +/* 경로 */ export const API_URL: string = import.meta.env.VITE_API_URL; export const SOCKETURL = import.meta.env.VITE_SOCKETIO_HOST; +/* API 공통 */ export const getToken = () => { const token = localStorage.getItem('token'); return token; diff --git a/src/apis/schedule.ts b/src/apis/schedule.ts index 8af9afe..d2d7648 100644 --- a/src/apis/schedule.ts +++ b/src/apis/schedule.ts @@ -25,6 +25,10 @@ export const getSchedule = async ( }, ); const data: IGetScheduleResponse = await res.json(); + if (data.msg === 'Schedule not found with name') { + await createNewScheduleName(name); + return getSchedule(name); + } return data.object['scheduleElements']; } catch (error) { throw error; @@ -117,3 +121,25 @@ export const deleteScheduleElement = async ( throw error; } }; + +const createNewScheduleName = async (name: string) => { + const token = getToken(); + try { + const res = await fetch(`${API_URL}/api/v1/schedule/addSchedule`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + name, + }), + }); + const data = await res.json(); + if (!data.success) { + throw new Error(data.msg); + } + } catch (error) { + throw error; + } +}; From 1f2af8eab3eb7902c49353a635a58e623bd8d7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sat, 17 Aug 2024 15:49:49 +0900 Subject: [PATCH 11/24] =?UTF-8?q?feat:=20=EC=8B=9C=EA=B0=84=ED=91=9C=20?= =?UTF-8?q?=EA=B2=B9=EC=B9=98=EB=A9=B4=20=EC=8B=9C=EA=B0=84=ED=91=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=A7=89=EB=8A=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/schedule.ts | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/utils/schedule.ts b/src/utils/schedule.ts index 199da9d..f5e7fb7 100644 --- a/src/utils/schedule.ts +++ b/src/utils/schedule.ts @@ -109,26 +109,27 @@ export const transformToScheduleElementDTO = (lectureData: LectureInfo) => { export const hasNewElementConflict = ( newElement: IAddScheduleElement, - existingElements: IScheduleElement[], + oldElements: IScheduleElement[], ): boolean => { - for (const existingElement of existingElements) { - if (newElement.dayOfWeek === existingElement.dayOfWeek) { - const startNew = new Date( - `1970-01-01T${newElement.startTime.slice(11)}`, - ).getTime(); - const endNew = new Date( - `1970-01-01T${newElement.endTime.slice(11)}`, - ).getTime(); - const startExisting = new Date( - `1970-01-01T${existingElement.startTime.slice(11)}`, - ).getTime(); - const endExisting = new Date( - `1970-01-01T${existingElement.endTime.slice(11)}`, - ).getTime(); + for (const oldElement of oldElements) { + if (newElement.dayOfWeek === oldElement.dayOfWeek) { + const startNewHour = Number(newElement.startTime.slice(11, 13)); + const startNewMinute = Number(newElement.startTime.slice(14, 16)) / 60; + const endNewHour = Number(newElement.endTime.slice(11, 13)); + const endNewMinute = Number(newElement.endTime.slice(14, 16)) / 60; + const startNewTime = startNewHour + startNewMinute; + const endNewTime = endNewHour + endNewMinute; + const startOldHour = Number(oldElement.startTime.slice(11, 13)); + const startOldMinute = Number(oldElement.startTime.slice(14, 16)) / 60; + const endOldHour = Number(oldElement.endTime.slice(11, 13)); + const endOldMinute = Number(oldElement.endTime.slice(14, 16)) / 60; + const startOldTime = startOldHour + startOldMinute; + const endOldTime = endOldHour + endOldMinute; if ( - (startNew < endExisting && startExisting < endNew) || - (startExisting < endNew && startNew < endExisting) + (startNewTime < endOldTime && endNewTime > startOldTime) || + (startOldTime < endNewTime && endOldTime > startNewTime) || + (startNewTime === startOldTime && endNewTime === endOldTime) ) { return true; } From 16d28645a852979f7fe618d28d04763c44fdb434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sat, 17 Aug 2024 17:16:25 +0900 Subject: [PATCH 12/24] =?UTF-8?q?fix:=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20?= =?UTF-8?q?=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=9E=90?= =?UTF-8?q?=EC=97=B0=EC=8A=A4=EB=9F=BD=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/landing.ts | 2 ++ src/pages/Landing/Landing.module.scss | 4 +-- src/pages/Landing/Landing.tsx | 38 ++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/constants/landing.ts b/src/constants/landing.ts index 0582535..6db6a38 100644 --- a/src/constants/landing.ts +++ b/src/constants/landing.ts @@ -1,6 +1,8 @@ export const SCROLLING_TEXTS = [ + '모두의 들을 권리를 위하여', '정확하지 못한 정보에 기대지 않도록', '신체의 불편함이 배움의 불편함이 되지 않도록', '배움을 향한 열정이 상처받지 않도록', '모두의 들을 권리를 위하여', + '정확하지 못한 정보에 기대지 않도록', ]; diff --git a/src/pages/Landing/Landing.module.scss b/src/pages/Landing/Landing.module.scss index 282ecd4..bdc97c8 100644 --- a/src/pages/Landing/Landing.module.scss +++ b/src/pages/Landing/Landing.module.scss @@ -266,10 +266,10 @@ display: flex; flex-direction: column; align-items: center; - height: 110px; + height: 100px; gap: 20px; - transition: all 0.3s ease; li { + display: flex; justify-content: center; align-items: center; height: 50px; diff --git a/src/pages/Landing/Landing.tsx b/src/pages/Landing/Landing.tsx index 9e49567..2db25d5 100644 --- a/src/pages/Landing/Landing.tsx +++ b/src/pages/Landing/Landing.tsx @@ -12,14 +12,38 @@ import { useEffect, useRef, useState } from 'react'; const Landing = () => { const [activeIndex, setActiveIndex] = useState(1); - const carouselRef = useRef(null); + const [transition, setTransition] = useState(true); + const intervalRef = useRef(null); - useEffect(() => { - const interval = setInterval(() => { - setActiveIndex((prevIndex) => (prevIndex + 1) % SCROLLING_TEXTS.length); + const startInterval = () => { + if (intervalRef.current) clearInterval(intervalRef.current); + + intervalRef.current = setInterval(() => { + setActiveIndex((prevIndex) => { + if (prevIndex === SCROLLING_TEXTS.length - 2) { + setTimeout(() => { + setActiveIndex(0); + setTransition(false); + + requestAnimationFrame(() => { + setActiveIndex(1); + setTransition(true); + }); + }, 300); + + return prevIndex; + } + setTransition(true); + return (prevIndex + 1) % SCROLLING_TEXTS.length; + }); }, 2000); + }; - return () => clearInterval(interval); + useEffect(() => { + startInterval(); + return () => { + if (intervalRef.current) clearInterval(intervalRef.current); + }; }, []); return ( @@ -144,9 +168,9 @@ const Landing = () => {
    {SCROLLING_TEXTS.map((text, index) => ( From e0543ec17f502ec3ed7a5dbd15721c0d05e50cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sat, 17 Aug 2024 17:34:52 +0900 Subject: [PATCH 13/24] =?UTF-8?q?feat:=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20?= =?UTF-8?q?=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=203=EC=A4=84?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=B4=EC=9D=B4=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/landing.ts | 1 + src/pages/Landing/Landing.module.scss | 2 +- src/pages/Landing/Landing.tsx | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/constants/landing.ts b/src/constants/landing.ts index 6db6a38..3354632 100644 --- a/src/constants/landing.ts +++ b/src/constants/landing.ts @@ -1,4 +1,5 @@ export const SCROLLING_TEXTS = [ + '정확하지 못한 정보에 기대지 않도록', '모두의 들을 권리를 위하여', '정확하지 못한 정보에 기대지 않도록', '신체의 불편함이 배움의 불편함이 되지 않도록', diff --git a/src/pages/Landing/Landing.module.scss b/src/pages/Landing/Landing.module.scss index bdc97c8..c65a3ab 100644 --- a/src/pages/Landing/Landing.module.scss +++ b/src/pages/Landing/Landing.module.scss @@ -266,7 +266,7 @@ display: flex; flex-direction: column; align-items: center; - height: 100px; + height: 150px; gap: 20px; li { display: flex; diff --git a/src/pages/Landing/Landing.tsx b/src/pages/Landing/Landing.tsx index 2db25d5..0ef77c0 100644 --- a/src/pages/Landing/Landing.tsx +++ b/src/pages/Landing/Landing.tsx @@ -22,11 +22,11 @@ const Landing = () => { setActiveIndex((prevIndex) => { if (prevIndex === SCROLLING_TEXTS.length - 2) { setTimeout(() => { - setActiveIndex(0); + setActiveIndex(1); setTransition(false); requestAnimationFrame(() => { - setActiveIndex(1); + setActiveIndex(2); setTransition(true); }); }, 300); @@ -169,7 +169,7 @@ const Landing = () => {
      From 540c7ec2f9b03b41d70cae83e599c8e49caf9971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sat, 17 Aug 2024 17:45:49 +0900 Subject: [PATCH 14/24] =?UTF-8?q?fix:=20setTimout=20=EC=98=A4=EC=B0=A8=20?= =?UTF-8?q?=EB=B0=A9=EC=A7=80=20=EC=9C=84=ED=95=B4=20301ms=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Landing/Landing.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/Landing/Landing.tsx b/src/pages/Landing/Landing.tsx index 0ef77c0..3b783c7 100644 --- a/src/pages/Landing/Landing.tsx +++ b/src/pages/Landing/Landing.tsx @@ -14,6 +14,7 @@ const Landing = () => { const [activeIndex, setActiveIndex] = useState(1); const [transition, setTransition] = useState(true); const intervalRef = useRef(null); + const timeoutRef = useRef(null); const startInterval = () => { if (intervalRef.current) clearInterval(intervalRef.current); @@ -21,7 +22,7 @@ const Landing = () => { intervalRef.current = setInterval(() => { setActiveIndex((prevIndex) => { if (prevIndex === SCROLLING_TEXTS.length - 2) { - setTimeout(() => { + timeoutRef.current = setTimeout(() => { setActiveIndex(1); setTransition(false); @@ -29,7 +30,7 @@ const Landing = () => { setActiveIndex(2); setTransition(true); }); - }, 300); + }, 301); return prevIndex; } @@ -43,6 +44,7 @@ const Landing = () => { startInterval(); return () => { if (intervalRef.current) clearInterval(intervalRef.current); + if (timeoutRef.current) clearTimeout(timeoutRef.current); }; }, []); From 5e71eefe13bd08bbeba00c4439017878f99238c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sat, 17 Aug 2024 17:58:05 +0900 Subject: [PATCH 15/24] =?UTF-8?q?fix:=20=EC=B4=88=EA=B8=B0=20index=202?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Landing/Landing.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Landing/Landing.tsx b/src/pages/Landing/Landing.tsx index 3b783c7..74d0e36 100644 --- a/src/pages/Landing/Landing.tsx +++ b/src/pages/Landing/Landing.tsx @@ -11,7 +11,7 @@ import { SCROLLING_TEXTS } from '../../constants/landing'; import { useEffect, useRef, useState } from 'react'; const Landing = () => { - const [activeIndex, setActiveIndex] = useState(1); + const [activeIndex, setActiveIndex] = useState(2); const [transition, setTransition] = useState(true); const intervalRef = useRef(null); const timeoutRef = useRef(null); @@ -30,7 +30,7 @@ const Landing = () => { setActiveIndex(2); setTransition(true); }); - }, 301); + }, 300); return prevIndex; } From 67d6ff6269802069d302c6f461888a4006838bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sat, 17 Aug 2024 18:15:52 +0900 Subject: [PATCH 16/24] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=A4=91=EB=B3=B5=EC=BD=94=EB=93=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Landing/Landing.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/Landing/Landing.tsx b/src/pages/Landing/Landing.tsx index 74d0e36..4b503a6 100644 --- a/src/pages/Landing/Landing.tsx +++ b/src/pages/Landing/Landing.tsx @@ -34,7 +34,6 @@ const Landing = () => { return prevIndex; } - setTransition(true); return (prevIndex + 1) % SCROLLING_TEXTS.length; }); }, 2000); From d877ec68666f8d7fbe51e5273240d5e0bc6de654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sun, 18 Aug 2024 18:00:23 +0900 Subject: [PATCH 17/24] =?UTF-8?q?fix:=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20?= =?UTF-8?q?=EC=99=84=EC=A0=84=20=EC=A0=95=EC=83=81=20=EA=B5=AC=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/landing.ts | 5 +++- src/pages/Landing/Landing.tsx | 49 ++++++++++++++--------------------- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/constants/landing.ts b/src/constants/landing.ts index 3354632..4bec55b 100644 --- a/src/constants/landing.ts +++ b/src/constants/landing.ts @@ -1,9 +1,12 @@ export const SCROLLING_TEXTS = [ - '정확하지 못한 정보에 기대지 않도록', + '배움을 향한 열정이 상처받지 않도록', '모두의 들을 권리를 위하여', + '정확하지 못한 정보에 기대지 않도록', '신체의 불편함이 배움의 불편함이 되지 않도록', '배움을 향한 열정이 상처받지 않도록', '모두의 들을 권리를 위하여', + '정확하지 못한 정보에 기대지 않도록', + '신체의 불편함이 배움의 불편함이 되지 않도록', ]; diff --git a/src/pages/Landing/Landing.tsx b/src/pages/Landing/Landing.tsx index 4b503a6..7fd94ee 100644 --- a/src/pages/Landing/Landing.tsx +++ b/src/pages/Landing/Landing.tsx @@ -1,3 +1,4 @@ +import { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import Logo from '../../assets/images/logo/landing-logo.svg?react'; import graph1 from '../../assets/images/landing/graph1.png'; @@ -6,46 +7,34 @@ import function1 from '../../assets/images/landing/function1.png'; import function2 from '../../assets/images/landing/function2.png'; import function3 from '../../assets/images/landing/function3.png'; import example from '../../assets/images/landing/landing-myscript.jpg'; -import styles from './Landing.module.scss'; import { SCROLLING_TEXTS } from '../../constants/landing'; -import { useEffect, useRef, useState } from 'react'; +import styles from './Landing.module.scss'; const Landing = () => { - const [activeIndex, setActiveIndex] = useState(2); - const [transition, setTransition] = useState(true); - const intervalRef = useRef(null); - const timeoutRef = useRef(null); + const FIRST_TEXT_INDEX = 2; + const LAST_TEXT_INDEX = SCROLLING_TEXTS.length - 3; - const startInterval = () => { - if (intervalRef.current) clearInterval(intervalRef.current); + const [activeIndex, setActiveIndex] = useState(FIRST_TEXT_INDEX); + const [transition, setTransition] = useState(true); - intervalRef.current = setInterval(() => { - setActiveIndex((prevIndex) => { - if (prevIndex === SCROLLING_TEXTS.length - 2) { - timeoutRef.current = setTimeout(() => { - setActiveIndex(1); - setTransition(false); + const next = () => { + setTransition(true); + setActiveIndex((prev) => prev + 1); - requestAnimationFrame(() => { - setActiveIndex(2); - setTransition(true); - }); - }, 300); + const transitionEndTimer = setTimeout(() => { + if (activeIndex === LAST_TEXT_INDEX) { + setTransition(false); + setActiveIndex(FIRST_TEXT_INDEX); + } + }, 300); - return prevIndex; - } - return (prevIndex + 1) % SCROLLING_TEXTS.length; - }); - }, 2000); + return () => clearTimeout(transitionEndTimer); }; useEffect(() => { - startInterval(); - return () => { - if (intervalRef.current) clearInterval(intervalRef.current); - if (timeoutRef.current) clearTimeout(timeoutRef.current); - }; - }, []); + const slideInterval = setInterval(next, 3000); + return () => clearInterval(slideInterval); + }, [next]); return (
      From 947ef2982b949e07126bd6e46a7922e113932ed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sun, 18 Aug 2024 19:23:17 +0900 Subject: [PATCH 18/24] =?UTF-8?q?fix:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=ED=8F=BC=EC=97=90=EC=84=9C=20=EB=B9=84=EB=B0=80?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=ED=91=9C=EC=8B=9C=20button=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20div=ED=83=9C=EA=B7=B8=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Auth/AuthForm/AuthForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Auth/AuthForm/AuthForm.tsx b/src/pages/Auth/AuthForm/AuthForm.tsx index f680f5f..6d6299d 100644 --- a/src/pages/Auth/AuthForm/AuthForm.tsx +++ b/src/pages/Auth/AuthForm/AuthForm.tsx @@ -153,12 +153,12 @@ const AuthForm = ({ onChange={(e) => setPasswordConfirm(e.target.value)} /> - +
); }; From bccdca9ce464990ff7a4f0cf0bc50f824af584de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sun, 18 Aug 2024 20:11:35 +0900 Subject: [PATCH 21/24] =?UTF-8?q?feat:=20=EC=8B=9C=EA=B0=84=EC=A0=9C?= =?UTF-8?q?=ED=95=9C=20=EC=84=A4=EC=A0=95=EC=8B=9C=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=ED=95=9C=20=EC=A0=9C=ED=95=9C=EC=8B=9C=EA=B0=84=EC=97=90=20?= =?UTF-8?q?=EB=8F=84=EB=8B=AC=ED=95=98=EB=A9=B4=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=EC=A2=85=EB=A3=8C=20=EB=B0=8F=20=EB=AC=B8=EC=A0=9C=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=95=88=EB=90=A0=20=EC=8B=9C=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TestOptionSelector.module.scss | 2 +- .../headers/TestHeader/TestHeader.tsx | 28 +++++++++++++------ src/store/useTestModalStore.ts | 2 -- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/components/organisms/TestOptionSelector/TestOptionSelector.module.scss b/src/components/organisms/TestOptionSelector/TestOptionSelector.module.scss index e311525..49e1648 100644 --- a/src/components/organisms/TestOptionSelector/TestOptionSelector.module.scss +++ b/src/components/organisms/TestOptionSelector/TestOptionSelector.module.scss @@ -74,7 +74,7 @@ label:before { background-color: $brand-point; border: 1px solid $brand-point; border-radius: 3px; - background-image: url('../../assets/images/check.svg'); + background-image: url('../../../assets/images/check.svg'); background-repeat: no-repeat; background-position: 50%; } diff --git a/src/components/organisms/headers/TestHeader/TestHeader.tsx b/src/components/organisms/headers/TestHeader/TestHeader.tsx index 5e3fcd4..955e670 100644 --- a/src/components/organisms/headers/TestHeader/TestHeader.tsx +++ b/src/components/organisms/headers/TestHeader/TestHeader.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { Link } from 'react-router-dom'; import TestModal from '../../../templates/modals/TestModal/TestModal'; import useTestModalStore from '../../../../store/useTestModalStore'; @@ -16,26 +16,26 @@ const TestHeader = ({ handleSubmit, showResults }: IProps) => { const [seconds, setSeconds] = useState(0); const timerIntervalRef = useRef(null); - const { testName } = useTestSettingsStore(); - const { isModalOpen, openModal } = useTestModalStore(); + const { testName, timeLimit } = useTestSettingsStore(); + const { isModalOpen, openModal, clearTestData } = useTestModalStore(); - const startTimer = () => { + const startTimer = useCallback(() => { if (timerIntervalRef.current !== null) return; timerIntervalRef.current = setInterval(() => { setSeconds((prev) => prev + 1); }, 1000); - }; + }, []); - const stopTimer = () => { + const stopTimer = useCallback(() => { if (timerIntervalRef.current === null) return; setSeconds(0); clearInterval(timerIntervalRef.current); timerIntervalRef.current = null; - }; + }, []); - const handleClickQuitBtn = () => { + const handleClickQuitBtn = useCallback(() => { if (!showResults) openModal(); - }; + }, []); useEffect(() => { startTimer(); @@ -46,6 +46,16 @@ const TestHeader = ({ handleSubmit, showResults }: IProps) => { if (showResults) stopTimer(); }, [showResults]); + useEffect(() => { + if (timeLimit != null) { + if (seconds >= timeLimit * 60) { + stopTimer(); + clearTestData(); + handleSubmit(); + } + } + }, [timeLimit, seconds]); + return (
diff --git a/src/store/useTestModalStore.ts b/src/store/useTestModalStore.ts index 5e11a15..70bd07b 100644 --- a/src/store/useTestModalStore.ts +++ b/src/store/useTestModalStore.ts @@ -1,7 +1,6 @@ import create from 'zustand'; interface ITestData { - time: number; completeNum: number; totalNum: number; } @@ -16,7 +15,6 @@ interface ITestModalState { } const initialTestData = { - time: 0, completeNum: 0, totalNum: 0, }; From bb0cdba75714260e8a93030b4e02dc7bc9b17fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Sun, 18 Aug 2024 20:19:32 +0900 Subject: [PATCH 22/24] =?UTF-8?q?fix:=20isLoading=20->=20isFetching?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Test/Test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Test/Test.tsx b/src/pages/Test/Test.tsx index 383bfc4..cddaba3 100644 --- a/src/pages/Test/Test.tsx +++ b/src/pages/Test/Test.tsx @@ -27,7 +27,7 @@ const Test = () => { problem_types: questionTypes.join(','), }; - const { data, isLoading } = useQuery({ + const { data, isFetching } = useQuery({ queryKey: ['problem', lectureId], queryFn: () => generateProblem(inputData), retry: false, @@ -69,7 +69,7 @@ const Test = () => {
- {isLoading && 문제 생성중...} + {isFetching && 문제 생성중...} {data != null && data.object != null && data.object.map((question, index) => ( From 73dbb87cdf57f23365f2645470c3b3ed8f0045b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Tue, 20 Aug 2024 20:14:58 +0900 Subject: [PATCH 23/24] =?UTF-8?q?feat:=20socket=EC=9D=98=20lecturdId?= =?UTF-8?q?=EC=97=90=20scheduleId=20=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RecordTagDropDown/RecordTagDropDown.tsx | 35 ++++++++++++++----- src/hooks/useSocket.ts | 4 ++- src/store/useRecordModalStore.ts | 7 ++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/components/molecules/RecordTagDropDown/RecordTagDropDown.tsx b/src/components/molecules/RecordTagDropDown/RecordTagDropDown.tsx index 201ae04..c66eaf9 100644 --- a/src/components/molecules/RecordTagDropDown/RecordTagDropDown.tsx +++ b/src/components/molecules/RecordTagDropDown/RecordTagDropDown.tsx @@ -1,6 +1,8 @@ -import { useMemo, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useQuery } from '@tanstack/react-query'; -import useRecordModalStore from '../../../store/useRecordModalStore'; +import useRecordModalStore, { + ITagItem, +} from '../../../store/useRecordModalStore'; import { IScheduleElement } from '../../../constants/schedule'; import { getSchedule } from '../../../apis/schedule'; import styles from './RecordTagDropDown.module.scss'; @@ -21,18 +23,33 @@ const RecordTagDropDown = () => { const TAGS = useMemo(() => { if (!data) return []; - return Array.from(new Set(data.map((item) => item.name))); + const tagObject: { [key: string]: number } = {}; + + data.forEach((item) => { + if (!tagObject.hasOwnProperty(item.name)) { + tagObject[item.name] = item.scheduleId; + } + }); + + return Object.entries(tagObject).map(([name, id]) => ({ + name, + scheduleElementId: id, + })); }, [data]); const handleTagBtnClick = () => { setIsTagBtnClicked((prev) => !prev); }; - const handleLiClick = (name: string) => { - updateRecordData({ tag: name }); + const handleLiClick = (item: ITagItem) => { + updateRecordData({ tag: item.name, scheduleId: item.scheduleElementId }); setIsTagBtnClicked(false); }; + useEffect(() => { + console.log(recordData); + }, [recordData]); + return (
{isTagBtnClicked && (
    - {TAGS.map((name) => ( + {TAGS.map((item) => (
  • handleLiClick(name)} + onClick={() => handleLiClick(item)} role="option" > - {name} + {item.name}
  • ))}
diff --git a/src/hooks/useSocket.ts b/src/hooks/useSocket.ts index 6830e65..0fde16f 100644 --- a/src/hooks/useSocket.ts +++ b/src/hooks/useSocket.ts @@ -1,9 +1,11 @@ import { useEffect, useRef } from 'react'; import { io, Socket } from 'socket.io-client'; import { SOCKETURL } from '../apis/index'; +import useRecordModalStore from '../store/useRecordModalStore'; export const useSocket = (onTransitionResult: (result: string) => void) => { const socketRef = useRef(null); + const { recordData } = useRecordModalStore(); useEffect(() => { socketRef.current = io(SOCKETURL, { @@ -20,7 +22,7 @@ export const useSocket = (onTransitionResult: (result: string) => void) => { socketRef.current.on('connect', () => { console.log('socket connected'); - const lectureId = '668cceb8ebef2b4462de0fb5'; + const lectureId = recordData.scheduleId; socketRef.current?.emit('lectureId', lectureId); }); diff --git a/src/store/useRecordModalStore.ts b/src/store/useRecordModalStore.ts index 31c9762..f025583 100644 --- a/src/store/useRecordModalStore.ts +++ b/src/store/useRecordModalStore.ts @@ -4,6 +4,12 @@ import { generateRecordingTitle } from '../utils/dateFormatters'; interface IRecordData { title: string; tag: string; + scheduleId: number | null; +} + +export interface ITagItem { + name: string; + scheduleElementId: number | null; } interface IRecordModalState { @@ -18,6 +24,7 @@ interface IRecordModalState { const initialRecordData = { title: generateRecordingTitle(), tag: '', + scheduleId: null, }; const useRecordModalStore = create((set) => ({ From bf95ef0a618fd5d1938421bd9acd83b38dc60de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=82=98=EC=97=B0?= Date: Tue, 20 Aug 2024 20:21:26 +0900 Subject: [PATCH 24/24] =?UTF-8?q?refactor:=20scheduleId=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../molecules/RecordTagDropDown/RecordTagDropDown.tsx | 4 ++-- src/store/useRecordModalStore.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/molecules/RecordTagDropDown/RecordTagDropDown.tsx b/src/components/molecules/RecordTagDropDown/RecordTagDropDown.tsx index c66eaf9..925574f 100644 --- a/src/components/molecules/RecordTagDropDown/RecordTagDropDown.tsx +++ b/src/components/molecules/RecordTagDropDown/RecordTagDropDown.tsx @@ -33,7 +33,7 @@ const RecordTagDropDown = () => { return Object.entries(tagObject).map(([name, id]) => ({ name, - scheduleElementId: id, + scheduleId: id, })); }, [data]); @@ -42,7 +42,7 @@ const RecordTagDropDown = () => { }; const handleLiClick = (item: ITagItem) => { - updateRecordData({ tag: item.name, scheduleId: item.scheduleElementId }); + updateRecordData({ tag: item.name, scheduleId: item.scheduleId }); setIsTagBtnClicked(false); }; diff --git a/src/store/useRecordModalStore.ts b/src/store/useRecordModalStore.ts index f025583..b4ca674 100644 --- a/src/store/useRecordModalStore.ts +++ b/src/store/useRecordModalStore.ts @@ -9,7 +9,7 @@ interface IRecordData { export interface ITagItem { name: string; - scheduleElementId: number | null; + scheduleId: number | null; } interface IRecordModalState {