Skip to content

Commit

Permalink
Merge pull request #108 from Senity-Waved/develop
Browse files Browse the repository at this point in the history
[🌊 DEPLOY] 인증 내역 수정 사항 및 refreshToken 에러 핸들링 배포 버전에 반영
  • Loading branch information
eeeyooon authored Apr 11, 2024
2 parents cc21242 + 189d691 commit 71718c3
Show file tree
Hide file tree
Showing 12 changed files with 80 additions and 81 deletions.
51 changes: 30 additions & 21 deletions src/components/verification/collection/VerificationItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -20,22 +21,22 @@ export default function VerificationItem({
isMine,
nickname,
content,
isLiked,
liked,
likesCount,
link,
selectedId,
setSelectedId,
}: IVerificationItem) {
const [liked, setLiked] = useState<boolean>(isLiked);
const [isLiked, setIsLiked] = useState<boolean>(liked);
const [likeCountNum, setLikeCountNum] = useState<number>(likesCount);
const isSelected = selectedId === verificationId;

const toggleLike = (event: React.MouseEvent<HTMLElement>) => {
event.stopPropagation();
if (liked) {
if (isLiked) {
deleteLikeApi(verificationId)
.then(() => {
setLiked(false);
setIsLiked(false);
getLikeCountApi(verificationId)
.then((data) => {
setLikeCountNum(data.likedCount);
Expand All @@ -48,7 +49,7 @@ export default function VerificationItem({
} else {
postLikeApi(verificationId)
.then(() => {
setLiked(true);
setIsLiked(true);
getLikeCountApi(verificationId)
.then((data) => {
setLikeCountNum(data.likedCount);
Expand Down Expand Up @@ -77,13 +78,21 @@ export default function VerificationItem({
{isMine && <SMineLabel>내 인증</SMineLabel>}
<SAuthor>{nickname}</SAuthor>
{link && (
<SLink href={link} target="_blank" onClick={clickLink}>
{link}
</SLink>
<SLinkWrapper>
<Image
src="/icons/icon-link.svg"
alt="인증링크 아이콘"
width={20}
height={20}
/>
<SLink href={link} target="_blank" onClick={clickLink}>
{link}
</SLink>
</SLinkWrapper>
)}
<SContent isSelected={isSelected}>{content}</SContent>
<SLikeWrapper>
<SLikeBtn type="button" onClick={toggleLike} isLiked={liked} />
<SLikeBtn type="button" onClick={toggleLike} isLiked={isLiked} />
<SLikeCount>{likeCountNum}</SLikeCount>
</SLikeWrapper>
</SWrapper>
Expand All @@ -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`
Expand Down
11 changes: 8 additions & 3 deletions src/components/verification/collection/VerificationList.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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]);

Expand Down
12 changes: 6 additions & 6 deletions src/components/verification/collection/VerificationPhotoItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@ export default function VerificationPhotoItem({
verificationId,
isMine,
imageUrl,
isLiked,
liked,
likesCount,
}: IPhotoItem) {
const [liked, setLiked] = useState<boolean>(isLiked);
const [isLiked, setIsLiked] = useState<boolean>(liked);
const [likeCountNum, setLikeCountNum] = useState<number>(likesCount);
const [isModalOpen, setModalOpen] = useState(false);
const openModal = () => setModalOpen(true);
const closeModal = () => setModalOpen(false);

const toggleLike = (event: React.MouseEvent<HTMLElement>) => {
event.stopPropagation();
if (liked) {
if (isLiked) {
deleteLikeApi(verificationId)
.then(() => {
setLiked(false);
setIsLiked(false);
getLikeCountApi(verificationId)
.then((data) => {
setLikeCountNum(data.likedCount);
Expand All @@ -52,7 +52,7 @@ export default function VerificationPhotoItem({
} else {
postLikeApi(verificationId)
.then(() => {
setLiked(true);
setIsLiked(true);
getLikeCountApi(verificationId)
.then((data) => {
setLikeCountNum(data.likedCount);
Expand All @@ -78,7 +78,7 @@ export default function VerificationPhotoItem({
<SShadow />
{isMine && <SMinePhotoLabel>내 인증</SMinePhotoLabel>}
<SLikeWrapperWhite>
<SLikeBtnWhite isLiked={liked} onClick={toggleLike} />
<SLikeBtnWhite isLiked={isLiked} onClick={toggleLike} />
<SLikeCountWhite>{likeCountNum}</SLikeCountWhite>
</SLikeWrapperWhite>
</SVerificationWrapper>
Expand Down
12 changes: 8 additions & 4 deletions src/lib/axios/serverInstance.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -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<IReissueResponse>(
Expand Down
2 changes: 1 addition & 1 deletion src/lib/axios/verification/collection/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/axios/verification/post/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
9 changes: 7 additions & 2 deletions src/pages/api/auth/reissue.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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<string>(
Expand Down
6 changes: 0 additions & 6 deletions src/pages/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ export default function Home({
const [expiresTime, setExpiresTime] = useState<number>(0);
const [readyReconnect, setReadyReconnect] = useState<boolean>(false);

console.log(expiresTime);

useEffect(() => {
async function fetchTokenExpiry() {
try {
Expand All @@ -83,8 +81,6 @@ export default function Home({
const currentTime = Date.now();
const timeUntilExpiry = expiresTime - currentTime;

console.log(timeUntilExpiry);

if (timeUntilExpiry < 60000) {
setReadyReconnect(true);
}
Expand All @@ -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: {
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/pages/profile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ export default function Profile({
<SProfileEtc>
<div>
<p>현재 버전</p>
<p>1.0.1</p>
<p>1.0.2</p>
</div>
</SProfileEtc>
<SwithdrawalBtnWrapper>
Expand Down
45 changes: 14 additions & 31 deletions src/pages/verification/collection/[challengeGroupId].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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<ISnackBarState>({
open: false,
text: '',
});

const { snackBarData, openSnackBar } = useSnackBar();
const [stampData, setStampData] = useState<number[]>([]);
const [challengeData, setChallengeData] = useState<ICollectionInfo>({
groupTitle: '',
Expand Down Expand Up @@ -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(
{
Expand All @@ -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 (
<Layout
Expand Down Expand Up @@ -178,12 +165,8 @@ export default function VeirificationCollection() {
/>
</>
)}
{snackBarState.open && (
<SnackBar
text={snackBarState.text}
type={snackBarState.type}
noFooter
/>
{snackBarData.open && (
<SnackBar text={snackBarData.text} type={snackBarData.type} noFooter />
)}
</Layout>
);
Expand Down
7 changes: 3 additions & 4 deletions src/pages/verification/post/[challengeGroupId].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/types/verification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 71718c3

Please sign in to comment.