Skip to content

Commit

Permalink
글-삭제기능-추가 (#43)
Browse files Browse the repository at this point in the history
* New : 글 삭제기능 추가

* New : 스낵바 추가 - 미완성
  • Loading branch information
jobkaeHenry authored Nov 20, 2023
1 parent c510756 commit c83c76e
Show file tree
Hide file tree
Showing 16 changed files with 164 additions and 13 deletions.
2 changes: 2 additions & 0 deletions client/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "./globals.css";
import CustomQueryClientProvider from "@/components/queryClient/CustomQueryClientProvider";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import GlobalLoadingPopup from "./../components/GlobalLoadingPopup";
import GlobalToast from "@/components/GlobalToast";

export const metadata: Metadata = {
title: `${nameOfApp} | ${oneLineMessage}`,
Expand All @@ -35,6 +36,7 @@ export default function RootLayout({ children, Modal }: RootLayoutInterface) {
<ThemeRegistry options={{ key: "mui" }}>
<GlobalStyles styles={OverrideCSS} />
<GlobalLoadingPopup />
<GlobalToast/>
{Modal}
<Box
sx={{
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/ErrorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const ErrorPage = ({
reset: () => void;
}) => {
useEffect(() => {
errorHandler(JSON.stringify(error));
errorHandler(error);
}, [error]);

return (
Expand Down
55 changes: 55 additions & 0 deletions client/src/components/GlobalToast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"use client";

import {
SnackbarVariant,
useGlobalSnackbarStore,
} from "@/store/useGlobalSnackbarStore";
import { CheckCircle, Error, Warning } from "@mui/icons-material";
import { Snackbar, SnackbarContent, Stack } from "@mui/material";

const GlobalToast = () => {
const { isOpen, variant, message, closeToast } = useGlobalSnackbarStore();
return (
<Snackbar
open={isOpen}
color={variant}
key={message}
onClose={closeToast}
autoHideDuration={3000}
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
sx={{ mb: 6 }}
>
<SnackbarContent
message={<SnackbarMessage variant={variant} message={message} />}
/>
</Snackbar>
);
};

const SnackbarMessage = ({
message,
variant,
}: {
message: string;
variant: SnackbarVariant;
}) => {
return (
<Stack direction="row" gap={1} alignItems="center">
{IconSelector(variant)}
{message}
</Stack>
);
};

const IconSelector = (variant: SnackbarVariant) => {
switch (variant) {
case "danger":
return <Error sx={{color:'red'}} />;
case "warning":
return <Warning sx={{color:'orange'}}/>;
default:
return <CheckCircle sx={{color:'green'}}/>;
}
};

export default GlobalToast;
11 changes: 6 additions & 5 deletions client/src/components/post/PostCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { PostInterface } from "@/types/post/PostInterface";
import { MoreVertOutlined } from "@mui/icons-material";

import {
Box,
Card,
Expand All @@ -28,6 +28,7 @@ import UserAvatar from "../user/info/UserAvatar";
import Link from "next/link";
import { USER_PAGE } from "@/const/clientPath";
import { useMyInfoQuery } from "@/queries/auth/useMyInfoQuery";
import PostCardOptionDropdown from "./PostCardOptionDropdown";

const PostCard = ({
postAttachUrls,
Expand Down Expand Up @@ -56,7 +57,6 @@ const PostCard = ({
() => currentUser?.userNo === createdBy,
[currentUser]
);

return (
<Card sx={{ display: "flex", gap: 2, p: 2 }}>
<Link href={USER_PAGE(createdBy)}>
Expand All @@ -81,6 +81,7 @@ const PostCard = ({
display: "flex",
flexDirection: "row",
gap: 1,
height: 24,
}}
>
{/* 타이틀 */}
Expand All @@ -98,9 +99,9 @@ const PostCard = ({
</Typography>
</Box>

<ButtonBase aria-label="settings" sx={{ p: 0, height: 24 }}>
{isMyPost && <MoreVertOutlined />}
</ButtonBase>
{isMyPost && (
<PostCardOptionDropdown postId={postNo}/>
)}
</Box>

{alcoholName && (
Expand Down
39 changes: 39 additions & 0 deletions client/src/components/post/PostCardOptionDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { useState } from "react";
import { MoreVertOutlined } from "@mui/icons-material";
import { ButtonBase, Menu, MenuItem } from "@mui/material";
import { useDeletePostMutation } from "@/queries/post/useDeletePostMutation";

type PostCardOptionDropdownProps = {
postId:number
};

const PostCardOptionDropdown = ({postId}: PostCardOptionDropdownProps) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);

const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const {mutate:deletePost}=useDeletePostMutation()

const handleClose = () => {
setAnchorEl(null);
};
return (
<>
<ButtonBase aria-label="settings" sx={{ p: 0 }} onClick={handleClick}>
<MoreVertOutlined />
</ButtonBase>
<Menu open={open} anchorEl={anchorEl} onClose={handleClose}>
<MenuItem onClick={()=>{
if(confirm('정말 삭제하시겠습니까?')){
deletePost(postId)
}
}}>삭제</MenuItem>
<MenuItem>수정</MenuItem>
</Menu>
</>
);
};

export default PostCardOptionDropdown;
4 changes: 3 additions & 1 deletion client/src/components/post/PostDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import useGetPostDetailQuery from "@/queries/post/useGetPostDetailQuery";
import PostCard from "./PostCard";
import { PostInterface } from "@/types/post/PostInterface";
import { CircularProgress } from "@mui/material";
interface PostDetailInterface {
postNo: string;
initialData: PostInterface;
}
const PostDetail = async ({ postNo, initialData }: PostDetailInterface) => {
const { data } = useGetPostDetailQuery(postNo, { initialData });
return <PostCard {...data} />;
//FIXME 포스트의 좋아요갯수가 업데이트 되지않음
return data ? <PostCard {...data} /> : <CircularProgress />;
};
export default PostDetail;
4 changes: 2 additions & 2 deletions client/src/queries/auth/useLoginMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ const useLoginMutation = () => {
router.refresh();
router.push(HOME);
},
onError: (error: AxiosError<{ detailMessage: string }>) =>
errorHandler(error.response?.data.detailMessage ?? "에러가 발생했니다"),
onError: (error) =>
errorHandler(error),
onSettled: () => {
setLoading(false);
},
Expand Down
4 changes: 4 additions & 0 deletions client/src/queries/auth/useSignupMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ 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";

const useSignupMutation = () => {
const { mutate: loginHandler } = useLoginMutation();
Expand All @@ -25,6 +26,9 @@ const useSignupMutation = () => {
onSettled: () => {
setLoading(false);
},
onError: (err) => {
errorHandler(err);
},
});
};

Expand Down
2 changes: 2 additions & 0 deletions client/src/queries/newPost/useNewPostMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ 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";

const useNewPostMutation = () => {
return useMutation({
mutationFn: async (formData: NewPostRequestInterface) => {
const data = await usePostNewPostFn(formData);
return data;
},
onError: (err) => errorHandler(err),
});
};

Expand Down
4 changes: 4 additions & 0 deletions client/src/queries/post/useDeletePostMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ 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";

export const useDeletePostMutation = () => {
const invalidatePreviousData = useInvalidatePostList();
Expand All @@ -10,6 +11,9 @@ export const useDeletePostMutation = () => {
onSuccess: () => {
invalidatePreviousData();
},
onError:(err)=>{
errorHandler(err)
}
});
};

Expand Down
4 changes: 4 additions & 0 deletions client/src/queries/post/useLikePostMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
import { getPostListInfiniteQueryKey } from "./useGetPostListInfiniteQuery";
import getTokenFromLocalStorage from "@/utils/getTokenFromLocalStorage";
import { POST_LIKE_URL } from "@/const/serverPath";
import errorHandler from "@/utils/errorHandler";
/**
* 좋아요를 수행하고, 게시글을 invalidation 하는 쿼리
* @returns
Expand All @@ -17,6 +18,9 @@ const useLikePostMutation = () => {
queryClient.invalidateQueries({
queryKey: getPostListInfiniteQueryKey.all,
}),
onError:(err)=>{
errorHandler(err)
}
});
};

Expand Down
4 changes: 4 additions & 0 deletions client/src/queries/post/useUnLikePostMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
import { getPostListInfiniteQueryKey } from "./useGetPostListInfiniteQuery";
import getTokenFromLocalStorage from "@/utils/getTokenFromLocalStorage";
import { POST_UN_LIKE_URL } from "@/const/serverPath";
import errorHandler from "@/utils/errorHandler";
/**
* 좋아요를 취소하고, 게시글을 invalidation 하는 쿼리
* @returns
Expand All @@ -17,6 +18,9 @@ const useLikePostMutation = () => {
queryClient.invalidateQueries({
queryKey: getPostListInfiniteQueryKey.all,
}),
onError:(err)=>{
errorHandler(err)
}
});
};

Expand Down
4 changes: 3 additions & 1 deletion client/src/queries/user/useFollowMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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";

const useFollowMutation = () => {
const queryClient = useQueryClient();
Expand Down Expand Up @@ -39,7 +40,8 @@ const useFollowMutation = () => {
/**
* Mutation 실패시 원래 QuerySnapShot정보로 롤백
*/
onError: (_err, queryFnParams, context) => {
onError: (err, queryFnParams, context) => {
errorHandler(err);
if (!context) {
return;
}
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,6 +6,7 @@ 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";

const useUnFollowMutation = () => {
const queryClient = useQueryClient();
Expand Down Expand Up @@ -42,7 +43,8 @@ const useUnFollowMutation = () => {
/**
* Mutation 실패시 원래 QuerySnapShot정보로 롤백
*/
onError: (_err, queryFnParams, context) => {
onError: (err, queryFnParams, context) => {
errorHandler(err)
if (!context) {
return;
}
Expand Down
21 changes: 21 additions & 0 deletions client/src/store/useGlobalSnackbarStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { create } from "zustand";

interface GlobalSnackbarStore {
isOpen: boolean;
message: string;
variant: SnackbarVariant;
fireToast: (message: string, variant?: SnackbarVariant) => void;
closeToast:()=>void
}
export type SnackbarVariant = "neutral" | "success" | "danger" | "warning";

export const useGlobalSnackbarStore = create<GlobalSnackbarStore>((set) => ({
isOpen: false,
message: "",
variant: "neutral",
fireToast: (message, variant = "neutral") =>
set({ isOpen: true, message, variant }),
closeToast: () => set((prev) => ({ ...prev, message: "", isOpen: false })),
}));

export const useFireToast =()=> useGlobalSnackbarStore((state)=>state.fireToast)
13 changes: 11 additions & 2 deletions client/src/utils/errorHandler.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
export default function errorHandler(error: string) {
console.log(error);
"use client";
// import { useGlobalSnackbarStore } from "@/store/useGlobalSnackbarStore";
import { isAxiosError } from "axios";

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("로그인 후 이용 가능합니다");
}
}

0 comments on commit c83c76e

Please sign in to comment.