Skip to content

Commit

Permalink
토스트팝업-구현 (#56)
Browse files Browse the repository at this point in the history
* Refactor : 리렌더 방지

* New : 글로벌팝업 에러핸들링 적용

* Minor : tsx -> ts 확장자 변경

* New : 글로벌팝업 적용

* New : 토큰제거로직 추가
  • Loading branch information
jobkaeHenry authored Nov 27, 2023
1 parent 006ae97 commit 65d3e68
Show file tree
Hide file tree
Showing 13 changed files with 61 additions and 36 deletions.
6 changes: 4 additions & 2 deletions client/src/components/ErrorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Button, Paper } from "@mui/material";
import hasErrorPage from "@/assets/images/hasError.png";
import Image from "next/image";
import { useEffect } from "react";
import errorHandler from "@/utils/errorHandler";
import { useErrorHandler } from "@/utils/errorHandler";

const ErrorPage = ({
error,
Expand All @@ -12,6 +12,8 @@ const ErrorPage = ({
error: Error & { digest?: string };
reset: () => void;
}) => {
const errorHandler = useErrorHandler();

useEffect(() => {
errorHandler(error);
}, [error]);
Expand All @@ -24,7 +26,7 @@ const ErrorPage = ({
flexDirection: "column",
alignItems: "center",
height: "calc(100vh - 56px)",
gap:2
gap: 2,
}}
>
<Image priority src={hasErrorPage} alt="에러임을 알림" />
Expand Down
12 changes: 8 additions & 4 deletions client/src/components/GlobalToast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { CheckCircle, Error, Warning } from "@mui/icons-material";
import { Snackbar, SnackbarContent, Stack } from "@mui/material";

const GlobalToast = () => {
const { isOpen, variant, message, closeToast } = useGlobalSnackbarStore();
const isOpen = useGlobalSnackbarStore((store) => store.isOpen);
const variant = useGlobalSnackbarStore((store) => store.variant);
const message = useGlobalSnackbarStore((store) => store.message);
const closeToast = useGlobalSnackbarStore((store) => store.closeToast);

return (
<Snackbar
open={isOpen}
Expand Down Expand Up @@ -44,11 +48,11 @@ const SnackbarMessage = ({
const IconSelector = (variant: SnackbarVariant) => {
switch (variant) {
case "danger":
return <Error sx={{color:'red'}} />;
return <Error sx={{ color: "red" }} />;
case "warning":
return <Warning sx={{color:'orange'}}/>;
return <Warning sx={{ color: "orange" }} />;
default:
return <CheckCircle sx={{color:'green'}}/>;
return <CheckCircle sx={{ color: "green" }} />;
}
};

Expand Down
10 changes: 5 additions & 5 deletions client/src/queries/auth/useLoginMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
import { MyInfoQueryKeys } from "./useMyInfoQuery";
import { useRouter } from "next/navigation";
import HOME from "@/const/clientPath";
import errorHandler from "@/utils/errorHandler";
import { AxiosError } from "axios";
import { useErrorHandler } from "@/utils/errorHandler";
import { useGlobalLoadingStore } from "@/store/useGlobalLoadingStore";

const useLoginMutation = () => {
const { loginHandler } = useLogin();
const queryClient = useQueryClient();
const router = useRouter();
const { setLoading } = useGlobalLoadingStore();
const errorHandler = useErrorHandler();

return useMutation({
mutationKey: LoginMuataionKey.all,
Expand All @@ -29,8 +29,7 @@ const useLoginMutation = () => {
router.refresh();
router.push(HOME);
},
onError: (error) =>
errorHandler(error),
onError: (error) => errorHandler(error),
onSettled: () => {
setLoading(false);
},
Expand All @@ -52,6 +51,7 @@ export const LoginMuataionKey = {
* @param id 유저아이디
* @returns 로그인뮤테이션 키
*/
byId: (id: SigninRequirement["id"]) => [...LoginMuataionKey.all, {id}] as const,
byId: (id: SigninRequirement["id"]) =>
[...LoginMuataionKey.all, { id }] as const,
};
export default useLoginMutation;
4 changes: 3 additions & 1 deletion client/src/queries/auth/useSignupMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { SignupRequirement } from "@/types/auth/signupRequirement";
import { useMutation } from "@tanstack/react-query";
import useLoginMutation from "./useLoginMutation";
import { useGlobalLoadingStore } from "@/store/useGlobalLoadingStore";
import errorHandler from "@/utils/errorHandler";
import { useErrorHandler } from "@/utils/errorHandler";

const useSignupMutation = () => {
const { mutate: loginHandler } = useLoginMutation();
const { setLoading } = useGlobalLoadingStore();
const errorHandler = useErrorHandler();

return useMutation({
mutationKey: signupMuataionKey.all,
mutationFn: async (formData: SignupRequirement) => {
Expand Down
3 changes: 2 additions & 1 deletion client/src/queries/newPost/useNewPostMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import axios from "@/libs/axios";
import { POST_LIST } from "@/const/serverPath";
import { NewPostRequestInterface } from "@/types/newPost/NewPostInterface";
import getTokenFromLocalStorage from "@/utils/getTokenFromLocalStorage";
import errorHandler from "@/utils/errorHandler";
import { useErrorHandler } from "@/utils/errorHandler";

const useNewPostMutation = () => {
const errorHandler = useErrorHandler();
return useMutation({
mutationFn: async (formData: NewPostRequestInterface) => {
const data = await usePostNewPostFn(formData);
Expand Down
9 changes: 5 additions & 4 deletions client/src/queries/post/useDeletePostMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import { REMOVE_POST } from "@/const/serverPath";
import { axiosPrivate } from "@/libs/axios";
import { useMutation } from "@tanstack/react-query";
import { useInvalidatePostList } from "./useGetPostListInfiniteQuery";
import errorHandler from "@/utils/errorHandler";
import { useErrorHandler } from "@/utils/errorHandler";

export const useDeletePostMutation = () => {
const invalidatePreviousData = useInvalidatePostList();
const errorHandler = useErrorHandler();
return useMutation({
mutationFn: (pk: number) => deletePostFn(pk),
onSuccess: () => {
invalidatePreviousData();
},
onError:(err)=>{
errorHandler(err)
}
onError: (err) => {
errorHandler(err);
},
});
};

Expand Down
7 changes: 4 additions & 3 deletions client/src/queries/post/useLikePostMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from "./useGetPostListInfiniteQuery";
import getTokenFromLocalStorage from "@/utils/getTokenFromLocalStorage";
import { POST_LIKE_URL } from "@/const/serverPath";
import errorHandler from "@/utils/errorHandler";
import { useErrorHandler } from "@/utils/errorHandler";
import { PostcardContextInterface } from "@/store/PostCardContext";
import { useOptimisticUpdatePostList } from "@/queries/post/updator/useOptimisticUpdatePostList";
import { useOptimisticUpdatePostDetail } from "./updator/useOptimisticUpdatePostDetail";
Expand All @@ -26,7 +26,8 @@ import { postDetailQueryKey } from "./useGetPostDetailQuery";
*/
const useLikePostMutation = (context?: PostcardContextInterface) => {
const queryClient = useQueryClient();


const errorHandler = useErrorHandler();
const postListUpdator = useOptimisticUpdatePostList({ type: "like" });
const postDetailUpdator = useOptimisticUpdatePostDetail({ type: "like" });

Expand All @@ -52,7 +53,7 @@ const useLikePostMutation = (context?: PostcardContextInterface) => {
);
// [디테일쿼리]
const detailQuerySnapshot = queryClient.getQueryData(
postDetailQueryKey.byId(String(id)),
postDetailQueryKey.byId(String(id))
);
// Optimastic Update
// [리스트 쿼리]
Expand Down
5 changes: 3 additions & 2 deletions client/src/queries/post/useUnLikePostMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from "./useGetPostListInfiniteQuery";
import getTokenFromLocalStorage from "@/utils/getTokenFromLocalStorage";
import { POST_UN_LIKE_URL } from "@/const/serverPath";
import errorHandler from "@/utils/errorHandler";
import { useErrorHandler } from "@/utils/errorHandler";
import { PostcardContextInterface } from "@/store/PostCardContext";
import { useOptimisticUpdatePostList } from "@/queries/post/updator/useOptimisticUpdatePostList";
import { useOptimisticUpdatePostDetail } from "./updator/useOptimisticUpdatePostDetail";
Expand All @@ -26,6 +26,7 @@ import { postDetailQueryKey } from "./useGetPostDetailQuery";
*/
const useLikePostMutation = (context?: PostcardContextInterface) => {
const queryClient = useQueryClient();
const errorHandler = useErrorHandler();

const postListUpdator = useOptimisticUpdatePostList({ type: "unlike" });
const postDetailUpdator = useOptimisticUpdatePostDetail({ type: "unlike" });
Expand Down Expand Up @@ -53,7 +54,7 @@ const useLikePostMutation = (context?: PostcardContextInterface) => {
);
// [디테일쿼리]
const detailQuerySnapshot = queryClient.getQueryData(
postDetailQueryKey.byId(String(id)),
postDetailQueryKey.byId(String(id))
);

// Optimastic Update
Expand Down
3 changes: 2 additions & 1 deletion client/src/queries/user/useFollowMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import { UserInfoQueryKey } from "./useUserInfoQuery";
import { UserInfoInterface } from "@/types/user/userInfoInterface";
import { MyInfoQueryKeys } from "../auth/useMyInfoQuery";
import { MyInfoInterface } from "@/types/auth/myInfo";
import errorHandler from "@/utils/errorHandler";
import { useErrorHandler } from "@/utils/errorHandler";

const useFollowMutation = () => {
const queryClient = useQueryClient();
const errorHandler = useErrorHandler();
return useMutation({
mutationFn: async (userNo: string) => await followUserMutatuibFn(userNo),
/**
Expand Down
4 changes: 3 additions & 1 deletion client/src/queries/user/useUnFollowMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import { UserInfoQueryKey } from "./useUserInfoQuery";
import { UserInfoInterface } from "@/types/user/userInfoInterface";
import { MyInfoQueryKeys } from "../auth/useMyInfoQuery";
import { MyInfoInterface } from "@/types/auth/myInfo";
import errorHandler from "@/utils/errorHandler";
import { useErrorHandler } from "@/utils/errorHandler";

const useUnFollowMutation = () => {
const queryClient = useQueryClient();
const errorHandler = useErrorHandler();

return useMutation({
mutationFn: async (userNo: string) => await followUserMutationFn(userNo),
/**
Expand Down
File renamed without changes.
4 changes: 1 addition & 3 deletions client/src/store/useGlobalSnackbarStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,4 @@ export const useGlobalSnackbarStore = create<GlobalSnackbarStore>((set) => ({
fireToast: (message, variant = "neutral") =>
set({ isOpen: true, message, variant }),
closeToast: () => set((prev) => ({ ...prev, message: "", isOpen: false })),
}));

export const useFireToast =()=> useGlobalSnackbarStore((state)=>state.fireToast)
}));
30 changes: 21 additions & 9 deletions client/src/utils/errorHandler.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
"use client";
// import { useGlobalSnackbarStore } from "@/store/useGlobalSnackbarStore";
import { useGlobalSnackbarStore } from "@/store/useGlobalSnackbarStore";
import { isAxiosError } from "axios";
import { useCallback } from "react";

export default function ErrorHandler(error: Error) {
// const { fireToast } = useGlobalSnackbarStore();
if (isAxiosError(error) && error.response) {
// FIXME : Zustand 사용 연구
// error.response.status === 401 && fireToast("로그인 후 이용 가능합니다");
error.response.status === 401 && console.log("로그인 후 이용 가능합니다");
}
}
/**
* Axios 에러의 status 코드를 판별해 적절한 토스트팝업을 표출해주는 함수를 리런하는 훅
* @returns errorHandler (error)=>void
*/
export const useErrorHandler = () => {
const fireToast = useGlobalSnackbarStore((state) => state.fireToast);

const errorHandler = useCallback((error: Error) => {
if (isAxiosError(error) && error.response) {
switch (error.response.status) {
case 401:
fireToast("로그인 후 이용 가능합니다");
// 토큰이 만료된 경우가 대부분이므로 토큰제거
localStorage.removeItem('accessToken')
}
}
}, []);
return errorHandler;
};

0 comments on commit 65d3e68

Please sign in to comment.