diff --git a/client/src/app/(protectedRoute)/new-post/page.tsx b/client/src/app/(protectedRoute)/new-post/page.tsx index 1ed3056..6d7243c 100644 --- a/client/src/app/(protectedRoute)/new-post/page.tsx +++ b/client/src/app/(protectedRoute)/new-post/page.tsx @@ -3,7 +3,7 @@ import { Box, Container, Paper, Tooltip } from "@mui/material"; import { useRouter } from "next/navigation"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useState } from "react"; import HOME from "@/const/clientPath"; import PictureIcon from "@/assets/icons/PictureIcon.svg"; import PinIcon from "@/assets/icons/PinIcon.svg"; @@ -21,6 +21,8 @@ import CustomAppbar from "@/components/CustomAppbar"; import SquareIconButton from "@/components/SquareIconButton"; import PreviewImageByURL from "@/components/PreviewImageByURL"; import NewPostTextEditor from "@/components/newpost/NewPostTextEditor"; +import useRenderAsDataUrl from "@/hooks/useRenderAsDataUrl"; +import SingleImageInput from "@/components/SingleImageInput"; export default function NewpostPage() { const { setLoading } = useGlobalLoadingStore(); @@ -38,52 +40,43 @@ export default function NewpostPage() { useState(); const [file, setFile] = useState(); - const [fileUrl, setFileUrl] = useState(); + const fileUrl = useRenderAsDataUrl(file); const [isSuccess, SetIsSuccess] = useState(false); - useEffect(() => { - if (!file) { - return; - } - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onloadend = () => setFileUrl(reader.result); - }, [file]); - const { mutateAsync: newPostHandler } = useNewPostMutation(); const { mutateAsync: attachFileHandler } = useNewAttachMutation(); const { mutateAsync: deletePostHandler } = useDeletePostMutation(); - const submitHandler = useCallback(async () => { - setLoading(true); - let postNo; - try { - const { postNo: res } = await newPostHandler({ - ...formValue, - alcoholNo, - }); - postNo = res; - if (file) { - try { - await attachFileHandler({ - file, - url: { pk: postNo, type: "POST" }, - }); - } catch { - deletePostHandler(postNo); - return; + const submitHandler = useCallback( + async (formValue: NewPostRequestInterface, file?: File) => { + setLoading(true); + let postNo; + try { + const { postNo: res } = await newPostHandler(formValue); + postNo = res; + if (file) { + try { + await attachFileHandler({ + file, + url: { pk: postNo, type: "POST" }, + }); + } catch { + deletePostHandler(postNo); + return; + } } + invalidatePreviousPost(); + SetIsSuccess(true); + router.push(HOME); + } catch { + return; + } finally { + setLoading(false); } - invalidatePreviousPost(); - SetIsSuccess(true); - router.push(HOME); - } catch { - return; - } finally { - setLoading(false); - } - }, [formValue, alcoholNo, router, file]); + }, + [router] + ); return ( @@ -92,7 +85,7 @@ export default function NewpostPage() { title="포스팅" appendButton="공유" disableAppend={isSuccess} - onClickAppend={submitHandler} + onClickAppend={()=>submitHandler({...formValue,alcoholNo},file)} /> @@ -127,17 +120,7 @@ export default function NewpostPage() { component={"label"} iconComponent={} > - { - if (e.target.files) { - setFile(e.target.files[0]); - } - }} - /> + setFile(file)} /> {/* 위치 */} diff --git a/client/src/components/SingleImageInput.tsx b/client/src/components/SingleImageInput.tsx new file mode 100644 index 0000000..969e3b4 --- /dev/null +++ b/client/src/components/SingleImageInput.tsx @@ -0,0 +1,32 @@ +import React, { InputHTMLAttributes } from "react"; + +interface SingleImageInputInterface + extends Omit< + InputHTMLAttributes, + "onChange" | "type" | "capture" | "style" | "name" + > { + onChange: (file: File) => void; +} + +const SingleImageInput = ({ + onChange, + ...others +}: SingleImageInputInterface) => { + return ( + { + if (e.target.files) { + onChange(e.target.files[0]); + } + }} + {...others} + /> + ); +}; + +export default SingleImageInput; diff --git a/client/src/components/post/PostCard.tsx b/client/src/components/post/PostCard.tsx index 6ef4f5b..4554ae9 100644 --- a/client/src/components/post/PostCard.tsx +++ b/client/src/components/post/PostCard.tsx @@ -101,7 +101,12 @@ const PostCard = ({ - {isMyPost && } + {isMyPost && ( + + )} {alcoholName && ( diff --git a/client/src/components/post/PostCardOptionDropdown.tsx b/client/src/components/post/PostCardOptionDropdown.tsx index 53b39ce..7b6e264 100644 --- a/client/src/components/post/PostCardOptionDropdown.tsx +++ b/client/src/components/post/PostCardOptionDropdown.tsx @@ -2,19 +2,36 @@ import React, { useState } from "react"; import { MoreVertOutlined } from "@mui/icons-material"; import { ButtonBase, Menu, MenuItem } from "@mui/material"; import { useDeletePostMutation } from "@/queries/post/useDeletePostMutation"; +import useDeleteAttachMutation from "@/queries/attach/useDeleteAttachMutation"; +import { useRouter } from "next/navigation"; +import HOME from "@/const/clientPath"; type PostCardOptionDropdownProps = { postId: number; + filePk?: string; }; -const PostCardOptionDropdown = ({ postId }: PostCardOptionDropdownProps) => { +const PostCardOptionDropdown = ({ + postId, + filePk, +}: PostCardOptionDropdownProps) => { const [anchorEl, setAnchorEl] = useState(null); const open = Boolean(anchorEl); + const router = useRouter(); const handleClick = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); }; - const { mutate: deletePost } = useDeletePostMutation(); + const { mutateAsync: deletePost } = useDeletePostMutation(); + const { mutateAsync: deleteFile } = useDeleteAttachMutation(); + + const deleteHandler = async () => { + if (confirm("정말 삭제하시겠습니까?")) { + await deletePost(postId); + filePk && (await deleteFile(filePk)); + router.push(HOME); + } + }; const handleClose = () => { setAnchorEl(null); @@ -25,15 +42,7 @@ const PostCardOptionDropdown = ({ postId }: PostCardOptionDropdownProps) => { - { - if (confirm("정말 삭제하시겠습니까?")) { - deletePost(postId); - } - }} - > - 삭제 - + 삭제 수정 diff --git a/client/src/components/user/info/drawer/UserInfoEditingForm.tsx b/client/src/components/user/info/drawer/UserInfoEditingForm.tsx index e0867b3..9f0dd26 100644 --- a/client/src/components/user/info/drawer/UserInfoEditingForm.tsx +++ b/client/src/components/user/info/drawer/UserInfoEditingForm.tsx @@ -9,13 +9,15 @@ import { Badge, } from "@mui/material"; import CameraIcon from "@/assets/icons/badge/CameraIcon.svg"; -import { useCallback, useContext, useEffect, useState } from "react"; +import { useCallback, useContext, useState } from "react"; import useNewAttachMutation from "@/queries/attach/useNewAttachMutation"; import useDeleteAttachMutation from "@/queries/attach/useDeleteAttachMutation"; import UserPageContext from "@/store/user/UserPageContext"; import CustomAppbar from "@/components/CustomAppbar"; import { useGlobalLoadingStore } from "./../../../../store/useGlobalLoadingStore"; import usePatchUserInfoMutation from "@/queries/user/usePatchUserInfoMutation"; +import useRenderAsDataUrl from "@/hooks/useRenderAsDataUrl"; +import SingleImageInput from "@/components/SingleImageInput"; const UserInfoEditingForm = () => { const { setIsEditing } = useContext(UserPageContext); @@ -25,8 +27,9 @@ const UserInfoEditingForm = () => { const { data } = useMyInfoQuery(); const [introduction, setIntroduction] = useState(data?.introduction); + const [file, setFile] = useState(); - const [fileUrl, setFileUrl] = useState(null); + const fileUrl = useRenderAsDataUrl(file); const { mutateAsync: attachFile } = useNewAttachMutation(); const { mutateAsync: removeFile } = useDeleteAttachMutation(); @@ -58,15 +61,6 @@ const UserInfoEditingForm = () => { setLoading(false); }; - useEffect(() => { - if (!file) { - return; - } - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onloadend = () => setFileUrl(reader.result); - }, [file]); - return ( <> { sx={{ width: 80, height: 80, border: "1px solid #ccc" }} /> - { - if (e.target.files) { - setFile(e.target.files[0]); - } - }} - style={{ display: "none" }} - /> + setFile(file)} /> diff --git a/client/src/hooks/useRenderAsDataUrl.tsx b/client/src/hooks/useRenderAsDataUrl.tsx new file mode 100644 index 0000000..468b315 --- /dev/null +++ b/client/src/hooks/useRenderAsDataUrl.tsx @@ -0,0 +1,23 @@ +import { useEffect, useState } from "react"; + +/** + * file 을 입력받아 dataUrl을 리턴하는 훅 + * @param file + * @returns fileDataUrl + */ +const useRenderAsDataUrl = (file: File | undefined) => { + const [fileUrl, setFileUrl] = useState(null); + + useEffect(() => { + if (!file) { + return; + } + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onloadend = () => setFileUrl(reader.result); + }, [file]); + + return fileUrl; +}; + +export default useRenderAsDataUrl;