Skip to content

Commit

Permalink
[BUG] 현재 api me 가 무한으로 요청됨 외 1건 (#386)
Browse files Browse the repository at this point in the history
* fix: (#371) me가 무한으로 불리는 오류 수정

Co-authored-by: jero_kang <inyeong-kang@users.noreply.github.com>

* refactor: 투표통계 페이지 폴더명 수정(-Page 붙이기)

* feat: 에러페이지 문구 수정 및 모바일 헤더 에러바운더리 적용, 로딩스피너 > 스켈레톤

* refactor: API fetch 함수에서 react query로 대체

* feat: (#376) 로그인 후 개인정보 등록 페이지로 라우팅

* refactor: 에러 바운더리에서 핸들러를 넣을 수 없어 핸들러 코드 각주로 임시처리

* feat: (#371) 에러바운더리에 에러(페이지) 컴포넌트 연결

* feat: 통계페이지 UI 수정, 통신 실패시 에러컴포넌트 등장, 토글 열리지 않도록 수정

* feat: 서비스 최상단에 전용 에러바운더리 적용

- 최상단에는 nav/global style사용할 수 없어 새로 제작

* feat: (#376) 로그인 후 필수정보가 입력되어있지 않으면 입력페이지로 리다이렉트

* fix: 로그인을 하지 않았는데 개인정보 입력 페이지로 넘어가는 오류 수정

---------

Co-authored-by: jero_kang <inyeong-kang@users.noreply.github.com>
  • Loading branch information
chsua and inyeong-kang authored Aug 14, 2023
1 parent a415eb2 commit c37fab6
Show file tree
Hide file tree
Showing 26 changed files with 226 additions and 68 deletions.
20 changes: 12 additions & 8 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,26 @@ import PostOptionProvider from '@hooks/context/postOption';

import router from '@routes/router';

import ErrorBoundaryForTopClass from '@pages/ErrorBoundaryForTopClass';

import { GlobalStyle } from '@styles/globalStyle';
import { theme } from '@styles/theme';

const queryClient = new QueryClient();

const App = () => (
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<GlobalStyle />
<AuthProvider>
<ErrorBoundaryForTopClass>
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<GlobalStyle />
<PostOptionProvider>
<RouterProvider router={router} />
<AuthProvider>
<RouterProvider router={router} />
</AuthProvider>
</PostOptionProvider>
</AuthProvider>
</ThemeProvider>
</QueryClientProvider>
</ThemeProvider>
</QueryClientProvider>
</ErrorBoundaryForTopClass>
);

export default App;
5 changes: 4 additions & 1 deletion frontend/src/components/common/Dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ export default function Dashboard() {

const handleLogoutClick = () => {
clearCookieToken('accessToken');
clearCookieToken('hasEssentialInfo');
clearLoggedInfo();
};

return (
<S.Container>
{userInfo ? <UserProfile userInfo={userInfo} /> : <GuestProfile />}
<ErrorBoundary>
{userInfo ? <UserProfile userInfo={userInfo} /> : <GuestProfile />}
</ErrorBoundary>
<S.CategorySectionWrapper>
<ErrorBoundary>
<Suspense fallback={<Skeleton isLarge={true} />}>
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/components/common/ErrorMessage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import IconButton from '../IconButton';
import SquareButton from '../SquareButton';
// import IconButton from '../IconButton';
// import SquareButton from '../SquareButton';

import * as S from './style';

export default function ErrorMessage({ errorHandler }: { errorHandler: () => void }) {
export default function ErrorMessage({ errorHandler }: { errorHandler?: () => void }) {
return (
<S.Wrapper>
<S.Title>⚠ 잠시 후 다시 시도해주세요.</S.Title>
<S.Description>요청하신 데이터를 불러오는데 실패했습니다.</S.Description>
<S.Direction>
{/* <S.Direction>
<SquareButton onClick={errorHandler} aria-label="다시 시도" theme="blank">
<S.RetryText>
<IconButton category="retry" />
다시 시도
</S.RetryText>
</SquareButton>
</S.Direction>
</S.Direction> */}
</S.Wrapper>
);
}
1 change: 1 addition & 0 deletions frontend/src/hooks/query/user/useModifyUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const useModifyUser = () => {
onError: (error, __, context) => {
queryClient.setQueryData([QUERY_KEY.USER_INFO], context?.previousNickname);
window.console.error('닉네임 변경에 실패했습니다.');
alert('닉네임 변경에 실패했습니다.');
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEY.USER_INFO] });
Expand Down
11 changes: 2 additions & 9 deletions frontend/src/hooks/query/user/useUserInfo.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';

import { User } from '@type/user';

Expand All @@ -7,20 +7,13 @@ import { getUserInfo } from '@api/userInfo';
import { QUERY_KEY } from '@constants/queryKey';

export const useUserInfo = (isLoggedIn: boolean) => {
const queryClient = useQueryClient();

const { data, error, isLoading, isError } = useQuery<User | null>(
[QUERY_KEY.USER_INFO, isLoggedIn],
() => getUserInfo(isLoggedIn),
{
cacheTime: 60 * 60 * 1000,
staleTime: 60 * 60 * 1000,
onSuccess: () => {
queryClient.invalidateQueries([QUERY_KEY.USER_INFO]);
},
onError: error => {
window.console.log('User Info Fetch Error', error);
},
suspense: true,
}
);

Expand Down
1 change: 1 addition & 0 deletions frontend/src/hooks/query/user/useWithdrawalMembership.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const useWithdrawalMembership = () => {
},
onError: () => {
window.console.error('회원 탈퇴에 실패했습니다.');
alert('회원 탈퇴에 실패했습니다.');
},
});

Expand Down
3 changes: 3 additions & 0 deletions frontend/src/pages/Error/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useNavigate } from 'react-router-dom';

import Layout from '@components/common/Layout';
import LogoButton from '@components/common/LogoButton';
import SquareButton from '@components/common/SquareButton';

import * as S from './style';
Expand All @@ -12,6 +13,8 @@ export default function Error({ message }: { message?: string }) {
<Layout isSidebarVisible={false}>
<S.Wrapper>
<S.Description>{message ? message : '요청 중 오류가 발생했습니다.'}</S.Description>
<LogoButton content="icon" style={{ width: '100px', height: '100px' }} />
<S.Text>오류가 지속되는 경우 votogether@gmail.com 로 문의해주세요.</S.Text>
<S.ButtonWrapper>
<SquareButton
theme="fill"
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/pages/Error/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ export const Description = styled.p`
text-align: center;
`;

export const Text = styled.p`
width: 90%;
color: gray;
font: var(--text-body);
text-align: center;
`;

export const ButtonWrapper = styled.div`
display: flex;
justify-content: space-between;
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/pages/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Component, ErrorInfo, ReactNode } from 'react';

import ErrorMessage from '@components/common/ErrorMessage';

interface ErrorBoundaryProps {
children: ReactNode;
}
Expand All @@ -26,7 +28,7 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {

render() {
if (this.state.hasError) {
return <div>{this.state.errorMessage}</div>;
return <ErrorMessage />;
}

return this.props.children;
Expand Down
77 changes: 77 additions & 0 deletions frontend/src/pages/ErrorBoundaryForTopClass.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { styled } from 'styled-components';

import ErrorMessage from '@components/common/ErrorMessage';

import { theme } from '@styles/theme';

import ErrorBoundary from './ErrorBoundary';

/* 가장 최상단에서 에러가 난 경우 보여줄 에러 바운더리.
* nav를 사용할 수 없고 글로벌 스타일드도 사용할 수 없음.
* 때문에 nav를 제거한 빈 헤더를 정의하고, 에러메세지 컴포넌트를 사용
*/
class ErrorBoundaryForTopClass extends ErrorBoundary {
render() {
if (this.state.hasError) {
return (
<>
<WideTemplateHeader />
<NarrowTemplateHeader />
<ErrorWrapper>
<ErrorMessage />
</ErrorWrapper>
</>
);
}

return this.props.children;
}
}

const WideTemplateHeader = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 70px;
position: fixed;
top: 0;
//글로벌 스타일 바깥쪽이라 var 적용되지 않음
background-color: #1f1f1f;
padding: 0 80px;
@media (max-width: ${theme.breakpoint.sm}) {
display: none;
visibility: hidden;
}
`;

const NarrowTemplateHeader = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
width: 100%;
height: 55px;
padding: 0 20px;
position: fixed;
top: 0;
background-color: #1f1f1f;
`;

const ErrorWrapper = styled.div`
margin-top: 20px;
@media (min-width: ${theme.breakpoint.sm}) {
margin-top: 50px;
}
`;

export default ErrorBoundaryForTopClass;
4 changes: 2 additions & 2 deletions frontend/src/pages/ErrorBoundaryWithNarrowHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import NarrowTemplateHeader from '@components/common/NarrowTemplateHeader';

import Error from './Error';
import ErrorBoundary from './ErrorBoundary';
import * as S from './ErrorBoundaryWithNarrowHeaderStyle';

class ErrorBoundaryWithNarrowHeader extends ErrorBoundary {
render() {
if (this.state.hasError) {
return (
<>
<NarrowTemplateHeader />
<S.Wrapper>{this.state.errorMessage}</S.Wrapper>
<Error message={this.state.errorMessage} />
</>
);
}
Expand Down
15 changes: 0 additions & 15 deletions frontend/src/pages/ErrorBoundaryWithNarrowHeaderStyle.ts

This file was deleted.

7 changes: 5 additions & 2 deletions frontend/src/pages/MyInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { useContext, ChangeEvent } from 'react';
import { Navigate, useNavigate } from 'react-router-dom';

import { AuthContext } from '@hooks/context/auth';
import { useModifyUser } from '@hooks/query/user/useModifyUser';
import { useWithdrawalMembership } from '@hooks/query/user/useWithdrawalMembership';
import { useText } from '@hooks/useText';
import { useToggle } from '@hooks/useToggle';

import { modifyNickname, withdrawalMembership } from '@api/userInfo';

import Accordion from '@components/common/Accordion';
import GuestProfile from '@components/common/Dashboard/GuestProfile';
import UserProfile from '@components/common/Dashboard/UserProfile';
Expand All @@ -26,6 +26,9 @@ import * as S from './style';
export default function MyInfo() {
const navigate = useNavigate();

const { mutate: modifyNickname } = useModifyUser();
const { mutate: withdrawalMembership } = useWithdrawalMembership();

const { isOpen, openComponent, closeComponent } = useToggle();
const { loggedInfo, clearLoggedInfo } = useContext(AuthContext);
const { text: newNickname, handleTextChange: handleNicknameChange } = useText(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { WrittenVoteOptionType } from '@type/post';
import { Size } from '@type/style';

import { useFetch } from '@hooks/useFetch';
import { useToast } from '@hooks/useToast';

import { getOptionStatistics } from '@api/voteResult';

import LoadingSpinner from '@components/common/LoadingSpinner';
import Toast from '@components/common/Toast';
import WrittenVoteOption from '@components/optionList/WrittenVoteOptionList/WrittenVoteOption';
import VoteStatistics from '@components/VoteStatistics';

Expand All @@ -27,13 +29,17 @@ export default function OptionStatistics({
size,
}: OptionStatisticsProps) {
const [isStatisticsOpen, setIsStatisticsOpen] = useState(false);
const { isToastOpen, openToast, toastMessage } = useToast();

const {
data: voteResult,
errorMessage,
isLoading,
} = useFetch(() => getOptionStatistics({ postId, optionId: voteOption.id }));

const toggleOptionStatistics = () => {
if (!voteResult) return openToast('투표 통계 불러오기를 실패했습니다.');

setIsStatisticsOpen(!isStatisticsOpen);
};

Expand All @@ -59,6 +65,11 @@ export default function OptionStatistics({
)}
{isStatisticsOpen && errorMessage}
</S.StatisticsContainer>
{isToastOpen && (
<Toast size="md" position="bottom">
{toastMessage}
</Toast>
)}
</S.Container>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import { useFetch } from '@hooks/useFetch';
import { getPost } from '@api/post';
import { getPostStatistics } from '@api/voteResult';

import ErrorMessage from '@components/common/ErrorMessage';
import IconButton from '@components/common/IconButton';
import Layout from '@components/common/Layout';
import LoadingSpinner from '@components/common/LoadingSpinner';
import NarrowTemplateHeader from '@components/common/NarrowTemplateHeader';
import Skeleton from '@components/common/Skeleton';
import VoteStatistics from '@components/VoteStatistics';

import { PATH } from '@constants/path';
Expand Down Expand Up @@ -51,24 +52,23 @@ export default function VoteStatisticsPage() {
</S.HeaderWrapper>
<S.Container>
<S.PageHeader>투표 통계</S.PageHeader>
{postError && <div>{postError}</div>}
{postError && <ErrorMessage />}
{isPostLoading && (
<S.LoadingWrapper>
<LoadingSpinner size="md" />
<Skeleton isLarge={true} />
</S.LoadingWrapper>
)}
{postDetail && (
<S.OptionContainer>
{voteResultError && <div>{voteResultError}</div>}
{voteResultError && <ErrorMessage />}
{isVoteResultLoading && (
<S.LoadingWrapper>
<LoadingSpinner size="sm" />
<Skeleton isLarge={true} />
</S.LoadingWrapper>
)}
{voteResultResponse && (
<VoteStatistics voteResultResponse={voteResultResponse} size="md" />
)}

{postDetail.voteInfo.options.map(option => {
const { postId, voteInfo } = postDetail;
return (
Expand Down
Loading

0 comments on commit c37fab6

Please sign in to comment.