diff --git a/src/components/verification/collection/VerificationItem.tsx b/src/components/verification/collection/VerificationItem.tsx index e55c82fe..6c30afa2 100644 --- a/src/components/verification/collection/VerificationItem.tsx +++ b/src/components/verification/collection/VerificationItem.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import styled from '@emotion/styled'; import { css } from '@emotion/react'; +import Image from 'next/image'; import { IVerificationInfo } from '@/types/verification'; import { deleteLikeApi, @@ -20,22 +21,22 @@ export default function VerificationItem({ isMine, nickname, content, - isLiked, + liked, likesCount, link, selectedId, setSelectedId, }: IVerificationItem) { - const [liked, setLiked] = useState(isLiked); + const [isLiked, setIsLiked] = useState(liked); const [likeCountNum, setLikeCountNum] = useState(likesCount); const isSelected = selectedId === verificationId; const toggleLike = (event: React.MouseEvent) => { event.stopPropagation(); - if (liked) { + if (isLiked) { deleteLikeApi(verificationId) .then(() => { - setLiked(false); + setIsLiked(false); getLikeCountApi(verificationId) .then((data) => { setLikeCountNum(data.likedCount); @@ -48,7 +49,7 @@ export default function VerificationItem({ } else { postLikeApi(verificationId) .then(() => { - setLiked(true); + setIsLiked(true); getLikeCountApi(verificationId) .then((data) => { setLikeCountNum(data.likedCount); @@ -77,13 +78,21 @@ export default function VerificationItem({ {isMine && 내 인증} {nickname} {link && ( - - {link} - + + 인증링크 아이콘 + + {link} + + )} {content} - + {likeCountNum} @@ -110,22 +119,22 @@ const SAuthor = styled.h3` margin-bottom: 0.5rem; `; +const SLinkWrapper = styled.div` + width: 100%; + display: flex; + align-items: center; + margin-bottom: 0.25rem; +`; + const SLink = styled.a` + display: block; color: ${({ theme }) => theme.color.middle}; font-size: ${({ theme }) => theme.fontSize.body4}; font-weight: ${({ theme }) => theme.fontWeight.body4}; - margin-bottom: 0.25rem; - display: flex; - align-items: center; - width: fit-content; - - &::before { - content: ''; - display: inline-block; - width: 20px; - height: 20px; - background: url('/icons/icon-link.svg') no-repeat center; - } + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; `; const ellipsisStyle = css` diff --git a/src/components/verification/collection/VerificationList.tsx b/src/components/verification/collection/VerificationList.tsx index 27aae6d9..a6b3e530 100644 --- a/src/components/verification/collection/VerificationList.tsx +++ b/src/components/verification/collection/VerificationList.tsx @@ -1,5 +1,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import styled from '@emotion/styled'; +import { AxiosError } from 'axios'; import { IVerificationInfo } from '@/types/verification'; import VerificationItem from './VerificationItem'; import VerificationPhotoItem from './VerificationPhotoItem'; @@ -62,9 +63,13 @@ export default function VerificationList({ setVerificationsData(veriData); setIsEmptyData(false); } catch (veriError) { - setVerificationsData([]); - setIsEmptyData(true); - console.error('날짜별 인증내역 불러오기 실패'); + const err = veriError as AxiosError; + const status = err.response?.status; + const statusText = err.response?.statusText; + if (status === 404 && statusText === 'Not Found') { + setVerificationsData([]); + setIsEmptyData(true); + } } }, [challengeGroupId, date]); diff --git a/src/components/verification/collection/VerificationPhotoItem.tsx b/src/components/verification/collection/VerificationPhotoItem.tsx index 1d30ec52..d64ea566 100644 --- a/src/components/verification/collection/VerificationPhotoItem.tsx +++ b/src/components/verification/collection/VerificationPhotoItem.tsx @@ -25,10 +25,10 @@ export default function VerificationPhotoItem({ verificationId, isMine, imageUrl, - isLiked, + liked, likesCount, }: IPhotoItem) { - const [liked, setLiked] = useState(isLiked); + const [isLiked, setIsLiked] = useState(liked); const [likeCountNum, setLikeCountNum] = useState(likesCount); const [isModalOpen, setModalOpen] = useState(false); const openModal = () => setModalOpen(true); @@ -36,10 +36,10 @@ export default function VerificationPhotoItem({ const toggleLike = (event: React.MouseEvent) => { event.stopPropagation(); - if (liked) { + if (isLiked) { deleteLikeApi(verificationId) .then(() => { - setLiked(false); + setIsLiked(false); getLikeCountApi(verificationId) .then((data) => { setLikeCountNum(data.likedCount); @@ -52,7 +52,7 @@ export default function VerificationPhotoItem({ } else { postLikeApi(verificationId) .then(() => { - setLiked(true); + setIsLiked(true); getLikeCountApi(verificationId) .then((data) => { setLikeCountNum(data.likedCount); @@ -78,7 +78,7 @@ export default function VerificationPhotoItem({ {isMine && 내 인증} - + {likeCountNum} diff --git a/src/lib/axios/serverInstance.ts b/src/lib/axios/serverInstance.ts index 040cd120..615af6d1 100644 --- a/src/lib/axios/serverInstance.ts +++ b/src/lib/axios/serverInstance.ts @@ -1,5 +1,5 @@ import axios, { AxiosError } from 'axios'; -import { getCookie, setCookie } from 'cookies-next'; +import { deleteCookie, getCookie, setCookie } from 'cookies-next'; import { GetServerSidePropsContext } from 'next'; import { CustomAxiosRequestConfig } from './axiosConfig'; @@ -38,10 +38,14 @@ const createServerInstance = (context: GetServerSidePropsContext) => { ) { try { const refreshToken = getCookie('refreshToken', { req: context.req }); + if (!refreshToken) { - throw new Error( - 'accessToken 재발급을 위한 refreshToken이 존재하지 않습니다.', - ); + deleteCookie('accessToken', { + req: context.req, + res: context.res, + path: '/', + }); + throw new Error('인증 정보가 만료되어 로그아웃 되었습니다.'); } const { data: reissueData } = await axios.post( diff --git a/src/lib/axios/verification/collection/api.ts b/src/lib/axios/verification/collection/api.ts index bf8257fc..9468a3d6 100644 --- a/src/lib/axios/verification/collection/api.ts +++ b/src/lib/axios/verification/collection/api.ts @@ -109,7 +109,7 @@ export const getQuizApi = async ( date: string, ): Promise<{ date: string; question: string }> => { const response = await axiosInstance.get( - `/verify/${groupId}/dates?quizDate=${date} 09:00:00.0`, + `/quiz/${groupId}/dates?quizDate=${date} 09:00:00.0`, ); // eslint-disable-next-line @typescript-eslint/no-unsafe-return return response.data; diff --git a/src/lib/axios/verification/post/api.ts b/src/lib/axios/verification/post/api.ts index 6a3280e3..73e8b1ea 100644 --- a/src/lib/axios/verification/post/api.ts +++ b/src/lib/axios/verification/post/api.ts @@ -43,7 +43,7 @@ export const postMyCommitVerifiactionApi = (groupId: number) => { export const getQuizApi = async ( groupId: string, ): Promise<{ date: string; question: string }> => { - const response = await axiosInstance.get(`/verify/${groupId}`); + const response = await axiosInstance.get(`/quiz/${groupId}`); // eslint-disable-next-line @typescript-eslint/no-unsafe-return return response.data; }; diff --git a/src/pages/api/auth/reissue.ts b/src/pages/api/auth/reissue.ts index cf93e6be..4f5bc3ff 100644 --- a/src/pages/api/auth/reissue.ts +++ b/src/pages/api/auth/reissue.ts @@ -1,6 +1,6 @@ import { NextApiRequest, NextApiResponse } from 'next'; import axios, { AxiosError } from 'axios'; -import { getCookie, setCookie } from 'cookies-next'; +import { deleteCookie, getCookie, setCookie } from 'cookies-next'; export default async function Reissue( req: NextApiRequest, @@ -11,9 +11,14 @@ export default async function Reissue( const refreshToken = getCookie('refreshToken', { req, res }); if (!refreshToken) { + deleteCookie('accessToken', { + req, + res, + path: '/', + }); return res .status(401) - .json({ message: '🚨 refresh Token이 존재하지 않습니다.' }); + .json({ message: '인증 정보가 만료되어 로그아웃 되었습니다.' }); } const response = await axios.post( diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index d3ae8c68..07f2b255 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -57,8 +57,6 @@ export default function Home({ const [expiresTime, setExpiresTime] = useState(0); const [readyReconnect, setReadyReconnect] = useState(false); - console.log(expiresTime); - useEffect(() => { async function fetchTokenExpiry() { try { @@ -83,8 +81,6 @@ export default function Home({ const currentTime = Date.now(); const timeUntilExpiry = expiresTime - currentTime; - console.log(timeUntilExpiry); - if (timeUntilExpiry < 60000) { setReadyReconnect(true); } @@ -102,7 +98,6 @@ export default function Home({ console.log('eventSource :', eventSource); console.log('기존 eventSoruce close'); } - console.log('SSE 연동 !'); const urlEndPoint = `${process.env.NEXT_PUBLIC_BASE_URL}/event/subscribe`; eventSource = new EventSource(urlEndPoint, { headers: { @@ -131,7 +126,6 @@ export default function Home({ }, }, ); - console.log('토큰 재발급 및 SSE 재연동'); connectEventSource(data.accessToken); timeoutId = setTimeout( // eslint-disable-next-line @typescript-eslint/no-misused-promises diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx index 41cbb3cb..e05e6cfd 100644 --- a/src/pages/profile/index.tsx +++ b/src/pages/profile/index.tsx @@ -371,7 +371,7 @@ export default function Profile({

현재 버전

-

1.0.1

+

1.0.2

diff --git a/src/pages/verification/collection/[challengeGroupId].tsx b/src/pages/verification/collection/[challengeGroupId].tsx index ab25c94b..8695c9f9 100644 --- a/src/pages/verification/collection/[challengeGroupId].tsx +++ b/src/pages/verification/collection/[challengeGroupId].tsx @@ -2,7 +2,6 @@ import { useEffect, useState } from 'react'; import { AxiosError } from 'axios'; import { useRouter } from 'next/router'; import styled from '@emotion/styled'; -import ISnackBarState from '@/types/snackbar'; import ONE_DAY from '@/constants/day'; import Layout from '@/components/common/Layout'; import Stamp from '@/components/verification/collection/Stamp'; @@ -20,11 +19,7 @@ export default function VeirificationCollection() { const challengeGroupId = router.query.challengeGroupId as string; const verificationType = router.query.type as string; const myChallengeId = router.query.myChallengeId as string; - const [snackBarState, setSnackBarState] = useState({ - open: false, - text: '', - }); - + const { snackBarData, openSnackBar } = useSnackBar(); const [stampData, setStampData] = useState([]); const [challengeData, setChallengeData] = useState({ groupTitle: '', @@ -79,13 +74,9 @@ export default function VeirificationCollection() { useEffect(() => { const handleRouting = ( snackBarText: string, - snackBarType: 'correct' | 'warning' = 'correct', + snackBarType: 'correct' | 'warning' = 'warning', ): void => { - setSnackBarState({ - open: true, - text: snackBarText, - type: snackBarType, - }); + openSnackBar(snackBarText, snackBarType); router .replace( { @@ -103,25 +94,21 @@ export default function VeirificationCollection() { .catch((error: Error) => console.error('쿼리스트링 제거 후 페이지 이동 실패', error), ); - setTimeout(() => { - setSnackBarState({ - open: false, - text: '', - }); - }, 3500); }; if (query.successSubmission) { - handleRouting('인증 제출이 완료되었습니다.'); + handleRouting('인증 제출이 완료되었습니다.', 'correct'); } if (query.duplicateSubmission) { handleRouting('오늘의 인증을 이미 완료했습니다.', 'warning'); } - }, [query, router, challengeGroupId, myChallengeId, verificationType]); - - const { snackBarData } = useSnackBar(); - useEffect(() => { - setSnackBarState(snackBarData); - }, [snackBarData]); + }, [ + query, + router, + challengeGroupId, + myChallengeId, + verificationType, + openSnackBar, + ]); return ( )} - {snackBarState.open && ( - + {snackBarData.open && ( + )} ); diff --git a/src/pages/verification/post/[challengeGroupId].tsx b/src/pages/verification/post/[challengeGroupId].tsx index abb8255a..d88c5dc7 100644 --- a/src/pages/verification/post/[challengeGroupId].tsx +++ b/src/pages/verification/post/[challengeGroupId].tsx @@ -62,10 +62,9 @@ export default function VerificationPost() { } } catch (error) { const err = error as AxiosError; - if ( - err.response && - err.response.data === '이미 오늘의 인증을 완료했습니다.' - ) { + const status = err.response?.status; + const statusText = err.response?.statusText; + if (status === 403 && statusText === 'Forbidden') { navigateToCollection({ duplicateSubmission: true }); } setIsLoading(false); diff --git a/src/types/verification.ts b/src/types/verification.ts index f67b6f78..e2a6d8c0 100644 --- a/src/types/verification.ts +++ b/src/types/verification.ts @@ -4,7 +4,7 @@ export interface IVerificationInfo { nickname: string; content: string; imageUrl: string; - isLiked: boolean; + liked: boolean; likesCount: number; verificationDate: string; // zonedDateTime link?: string | null;