주요 기능 | 게시판 - itsyuna/Foot-Salon GitHub Wiki

Play / Half-Time

Redux Toolkit, Thunk를 사용하여 Data, Store, Module 관리

React Hook Form을 활용하여 form 작성

로그인 시 게시글 작성 / 게시글 보기 가능

게시글,댓글 - 작성자 기준 '수정' / '삭제' 버튼 활성화


✔️ 게시글 작성/읽기/업데이트/삭제

✔️ 최신순/오래된 순으로 게시글 정렬

✔️ 이미지 업로드

  • 업로드 파일 미리 보기

✔️ 댓글 기능

  • 댓글 작성/읽기/업데이트/삭제
  • 댓글 수 표시
  • '첫 댓글', 수정 시 수정 시각 & '수정됨' 문구 추가

💻 Code

store/playBoard.tsx
export const fetchPlayBoard = createAsyncThunk(
  "board/fetchPlayBoard",
  async () => {
    const collectData = collection(
      dbService,
      "play"
    ) as CollectionReference<BoardContents>;

    const orderData = query(collectData, orderBy("dateTime", "desc"));

    const querySnapshot = await getDocs(orderData);

    const playBoard = querySnapshot.docs.map((doc) => ({
      id: doc.id,
      board: doc.data(),
    }));

    return playBoard;
  }
);

const initialBoardState: BoardListItems[] = [];

const boardSlice = createSlice({
  name: "playBoard",
  initialState: {
    boardArray: initialBoardState,
  },
  reducers: {},
  extraReducers: (builder) => {
    builder.addCase(fetchPlayBoard.fulfilled, (state, action) => {
      state.boardArray = action.payload;
    });
  },
});

export const boardActions = boardSlice.actions;

export default boardSlice.reducer;
PostEditor.tsx
const PostEditor = ({ isEdit }: { isEdit: boolean }) => {
   ...

   // React hook form의 useForm 사용
   const {
     handleSubmit,
     control,
     formState: { errors },
   } = useForm<BoardFormData>();

   ...

return isEdit && !targetPost ? (
   // Edit 모드 & 해당 게시글이 없을 때 에러 메시지 표시
    <NoPostMessage />
  ) : (
    <BoardCard>
      <Form onSubmit={handleSubmit(onSubmit)}>
        <section>
          <CategoryBox>
            <CategoryName>작성자</CategoryName>
            <UserNickname>{userNickname}</UserNickname>
          </CategoryBox>
          <CategoryBox>
            <CategoryName>리그</CategoryName>
            <CategoryData>
              // React hook form의 Controller 사용
              <Controller
                control={control}
                defaultValue={targetPost?.board.league}
                name="league"
                rules={{
                  ...(!isEdit && {
                    required: "필수 입력사항입니다.",
                  }),
                }}
                render={({ field }) => (
                  <Select
                    option={optionList}
                    onChange={field.onChange}
                    defaultValue={targetPost?.board.league}
                    backgroundColor="#f6edd9"
                    color="#379237"
                    border="#7a9972"
                  ></Select>
                )}
              />
            </CategoryData>
            // 필수 입력 사항에 빈 input이 있을 시 에러 메시지 표시
            <ErrorText>{errors.league && errors.league.message}</ErrorText>
          </CategoryBox>
     ...
BoardList.tsx
// 최신순/오래된 순으로 게시글 정렬
const getListByOption = useCallback(() => {
  const compare = (a: BoardListItems, b: BoardListItems) => {
    if (sortList === "latest") {
      return (
        new Date(b.board.createdAt).getTime() -
        new Date(a.board.createdAt).getTime()
      );
    } else
      return (
        new Date(a.board.createdAt).getTime() -
        new Date(b.board.createdAt).getTime()
      );
  };
	
  // 원본 데이터를 보존하기 위해 copy해서 사용
  const copyList: BoardListItems[] = JSON.parse(
    JSON.stringify(boardByleague.map((item) => item))
  );

  const filterList = copyList.sort(compare);
  return filterList;
}, [boardByleague, sortList]);
...
Commnets.tsx
const editCommentSubmitHandler = async (data: CommentFormData) => {
    // 수정 시 수정 시각 반영
    const editCommentItems = {
      creatorId: userId,
      userNickname,
      contents: data.comment,
      createdAt: getDate(),
      dateTime: list.comment.dateTime,
      isEdit: true,
    };
    ...
}

return (
     ...
     // 첫 댓글 & '수정됨' 문구 추가
     <NicknameDate editComment={editComment}>
       <h3>{list.comment.userNickname}</h3>
       <h4>{list.comment.createdAt}</h4>
       {idx === 0 && <FirstComment>첫 댓글</FirstComment>}
       {list.comment.isEdit && <EditText>수정됨</EditText>}
     </NicknameDate>
     ...

🖥 View

게시글 리스트 Board list
게시글 업로드

🔻 게시글 업로드
Post editor


🔻 With photo (Preview)
Post editor with preview of photo

게시글 보기 Read post with photo
게시글 수정 Edit post
게시글이 없을 시 게시글이 없을 시
댓글

🔻 댓글 보기
Comments


🔻 댓글 수정
Edit comments

에러 처리

🔻 해당 번호의 게시글이 없을 시
해당 게시글이 없을 시

⚠️ **GitHub.com Fallback** ⚠️