커뮤니티 게시글 등록
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 };
};