school eats) 커뮤니티 - CRUD(with. react-query)

김민수·2024년 2월 12일

school eats 프로젝트

목록 보기
9/12
post-thumbnail

커뮤니티 게시글 등록

const postSchema = yup
  .object({
    title: yup.string().required('제목이 필요합니다.').max(100, '제목은 100자 이하 입니다.'),
    contents: yup.string().required('내용이 필요합니다.').max(5000, '내용은 5000자 이하 입니다.'),
  })
  .required();

export const useWriteBoardPost = () => {
  const [image, setImage] = useState<File | null>(null);
  const [uploading, setUploading] = useState(false);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const router = useRouter();
  const email = useRecoilValue(userEmail);

  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
    resolver: yupResolver(postSchema),
  });

  const success = () => {
    Modal.success({
      content: '게시물 등록에 성공하였습니다.',
    });
  };

  const onImageChange = (event: { target: { files: File[] } }) => {
    if (event.target.files[0]) {
      const file = event.target.files[0];

      setImage(file);
    }
  };

  const uploadImage = async () => {
    if (image) {
      const storage = getStorage();

      const storageRef = ref(storage, `board/${image.name}`);
      setUploading(true);
      try {
        const snapshot = await uploadBytes(storageRef, image);
        const url = await getDownloadURL(snapshot.ref);
        setUploading(false);
        return url;
      } catch (error) {
        alert('Error uploading image: ' + error);
        setUploading(false);
        return null;
      }
    }
    return null;
  };

  const onSubmit = async (data: { title: string; contents: string }) => {
    if (isSubmitting) return; // 이미 제출 중이면 추가 제출 방지
    setIsSubmitting(true); // 제출 상태로 변경
    const imageUrl = await uploadImage();
    const board = collection(db, 'board');
    await addDoc(board, {
      title: data.title,
      contents: data.contents,
      timestamp: new Date(),
      email,
      img: imageUrl,
      commentscount: 0,
      likecount: 0,
    });
    success();
    setIsSubmitting(false); // 제출 상태 해제
    router.push('/boards');
  };

  return { register, handleSubmit, errors, onSubmit, onImageChange, uploading, isSubmitting };
};

게시물 불러오기 (react-query)

import { doc, getDoc } from 'firebase/firestore';
import { db } from '../../pages/_app';
import { useQuery } from 'react-query';

interface Post {
  timestamp: string;
  email: string;
  title: string;
  contents: string;
  img: any;
}
const formatDate = (date: Date) => {
  const year = date.getFullYear().toString().slice(-2); // 뒤의 두 자리 숫자만 추출
  const month = (date.getMonth() + 1).toString().padStart(2, '0'); // 월 (0부터 시작하므로 1을 더함)
  const day = date.getDate().toString().padStart(2, '0'); // 일
  const hours = date.getHours().toString().padStart(2, '0'); // 시간
  const minutes = date.getMinutes().toString().padStart(2, '0'); // 분

  return `${year}/${month}/${day} ${hours}:${minutes}`;
};

const fetchPost = async (postId: string): Promise<Post> => {
  const postRef = doc(db, 'board', postId);
  const postDoc = await getDoc(postRef);
  const postData = postDoc.data();
  const timestamp = postData?.timestamp ? postData.timestamp.toDate() : '';
  const formattedDate = formatDate(timestamp);
  return {
    ...postData,
    timestamp: formattedDate,
    email: postData?.email,
    title: postData?.title,
    contents: postData?.contents,
    img: postData?.img,
  };
};

export const useGetDetailBoardPost = (postId: string) => {
  return useQuery(['board', postId], () => fetchPost(postId), {
    enabled: !!postId,
  });
};

게시물 삭제

  const onClickDeletePost = async () => {
    try {
      const postRef = doc(db, 'board', postId);
      const postData = (await getDoc(postRef)).data();

      await deleteDoc(postRef);

      // 게시물에 이미지가 있는 경우, Firebase Storage에서 이미지 삭제
      if (postData?.img) {
        const imageRef = ref(storage, postData.img);
        await deleteObject(imageRef);
      }

      router.push('/boards');
    } catch (error) {
      console.error('게시물 삭제 중 오류 발생:', error);
    }
  };

게시물 수정

const postSchema = yup
  .object({
    title: yup.string().required('제목이 필요합니다.').max(100, '제목은 100자 이하 입니다.'),
    contents: yup.string().required('내용이 필요합니다.').max(5000, '내용은 5000자 이하 입니다.'),
  })
  .required();

export const useEditBoardPost = (postId: string) => {
  const router = useRouter();
  const email = useRecoilValue(userEmail);
  const { post } = useGetDetailBoardPost();
  const [isSubmitting, setIsSubmitting] = useState(false);

  const {
    register,
    handleSubmit,
    formState: { errors },
    reset,
  } = useForm({
    resolver: yupResolver(postSchema),
    defaultValues: {},
  });

  useEffect(() => {
    if (post) {
      reset({
        title: post.title,
        contents: post.contents,
      });
    }
  }, [post, reset]);

  const success = () => {
    Modal.success({
      content: '게시물 수정에 성공하였습니다.',
    });
  };

  const [image, setImage] = useState<File | null>(null);
  const [uploading, setUploading] = useState(false);

  const onImageChange = (event: any) => {
    if (event.target.files[0]) {
      setImage(event.target.files[0]);
    }
  };

  const uploadImage = async () => {
    if (image) {
      const storage = getStorage();
      const storageRef = ref(storage, `board/${image.name}`);
      setUploading(true);
      try {
        const snapshot = await uploadBytes(storageRef, image);
        const url = await getDownloadURL(snapshot.ref);
        setUploading(false);
        return url;
      } catch (error) {
        console.error('Error uploading image: ', error);
        setUploading(false);
        return null;
      }
    }
    return null;
  };

  const onSubmit = async (data: { title: string; contents: string }) => {
    if (isSubmitting) return; // 이미 제출 중이면 추가 제출 방지
    setIsSubmitting(true); // 제출 상태로 변경
    const imageUrl = await uploadImage();
    const boardDoc = doc(db, 'board', postId);

    await updateDoc(boardDoc, {
      title: data.title,
      contents: data.contents,
      timestamp: new Date(),
      email,
      ...(imageUrl && { img: imageUrl }), // 새 이미지가 있으면 img 필드 업데이트
    });
    // 새 이미지 업로드 후 기존 이미지 삭제

    if (imageUrl && post?.img) {
      const oldImageRef = ref(storage, post.img);
      await deleteObject(oldImageRef).catch((error) => console.error('Error deleting old image:', error));
    }

    success();
    setIsSubmitting(false); // 제출 상태 해제
    router.push('/boards');
  };

  return { register, handleSubmit, errors, onSubmit, onImageChange, uploading, isSubmitting };
};

0개의 댓글