두 달간의 프로젝트 회고 (1)

돌리의 하루·2023년 6월 1일
0

너무 오랜만의 회고가 되어버렸다 ..!

4월 3일 이후 시작한 pre-project, main-project가 정확히 어제부로 마무리 되었고,

오늘은 그동안 내가 해온 것들에 대해서 정리하려는 시간을 가져보려고 한다.

  1. 우선, 4월 10 ~ 4월 27일 까지 해온 pre-project의 목표는

stackoverflow 클론코딩이었다.

스택오버플로우를 클론코딩 하는 부분이었는데,

우리팀은 크게 공통부분인 header,footer, sidebar

페이지 부분인 questions,tags,users, Home으로 나누어서 진행하기로 했다.

내가 맡은 부분은 Home, Questions, Tags 부분이었다.

home과 questions 부분은 거의 유사했다.

우선 한 일은, layout으로 header와 footer, sidebar의 공통영역과 page 내용을 분리하는 것이었다.

const MainContent = styled.div`
  display: flex;
`;

const Layout = (props) => {
  const { children } = props;
  return (
    <>
      <Header />
      <MainContent>
        <Sidebar />
        {children}
      </MainContent>
      <Footer />
    </>
  );
};

layout으로 구역설정을 한 후에, question component를 만들어 list를 불러오는 형식으로 코드를 구성했다.

const Question = ({ question }) => {
  const { title, content, tag, name, createdAt } = question;

  const navigate = useNavigate();
  function handleDummyClick(questionId) {
    const newUrl = `/questions/${questionId}`; // 경로와 id 값을 조합하여 새로운 URL 생성
    navigate(newUrl); // useNavigate Hook을 사용하여 새로운 URL로 이동
  }

  // const handleOneClick = () => {
  //   navigate(`/questions/question_id`);
  // };
  const tags = Array.isArray(tag) ? tag.slice(0, 5) : [];
  //밑의 부분은 현재 시간을 가져오는 함수다. 심심해서 그냥 만들어봤따
  // const createdAt = new Date().toLocaleString();
  return (
    <QuestionContainer>
      <div
        className="question-id"
        onClick={() => handleDummyClick(question.questionId)}
      >
        <div className="question-title">{title}</div>
        <div className="question-content">{content}</div>
        <div className="name-box">
          <div className="question-tag">
            {/* tag가 배열이 아닐 때의 조건도 추가해야함 최소 0개에서 최대 5개까지 허용가능범위*/}
            {/* tag가 배열이 아니라면 빈칸을 렌더링 하고, 배열이라면 map으로 뿌리고 span으로 감싼다 */}
            {/* 필터링 기준이 1번인지 2번인지에 따라 주석 해제할것 */}
            {tags.map((el) => (
              <div>
                <span>{el}</span>
              </div>
            ))}
          </div>
          <div className="name-sub">
            <div className="question-name">{name}</div>
            <div className="question-createAt">{createdAt}</div>
          </div>
        </div>
      </div>
    </QuestionContainer>
  );
};
const QuestionList = ({ questions }) => {
  return (
    <QuestionListContainer>
      {questions.map((question) => (
        <QuestionListItem key={question.id}>
          <QuestionTitle>{question.title}</QuestionTitle>
          <QuestionBody>{question.body}</QuestionBody>
        </QuestionListItem>
      ))}
    </QuestionListContainer>
  );
};

이 외에는 CSS에 시간을 좀 더 쏟았던 것 같다.

내가 시간을 많이 쏟은 부분은 Tags 부분이었다.

Tags 부분은 tag를 만들고, tags리스트를 만드는 부분은 위 questions,home 부분과 똑같다.

그러나, tags부분은 페이지네이션이 필요했고, input의 filter조건을 태그로 지정해줘야하는 시

도가 처음이다보니, 많이 헤맸다.

//TagSearch
const TagSearch = () => {
  const [questions, setQuestions] = useState(qsdummydata);

  return (
    <Layout>
      <HeadContainer>
        <div className="questions-number">{qsdummydata.length} questions</div>
        <div className="questions-box">
          {questions.map((el) => (
            <Question key={el.id} question={el} />
          ))}
        </div>
      </HeadContainer>
    </Layout>
  );
};
//Tags
const Tags = () => {
  const [tags, setTags] = useState([]);
  const [inputValue, setInputValue] = useState("");
  const [count, setCount] = useState(20);
  const [currentPage, setCurrentPage] = useState(1);
  const [tagsPerPage, setTagsPerPage] = useState(12);
  //tagsPerPage는 tagbox기준! 페이지 버튼아님


  //마지막 페이지 계산 //9
  const indexOfLastTag = currentPage * tagsPerPage;
  // 12 0

  //첫 번째 페이지 : 마지막 페이지에서 tagsPerPage뺌 //0
  const indexOfFirstTag = indexOfLastTag - tagsPerPage;


  const currentTags = tags.length > 0 ? tags.slice(indexOfFirstTag, indexOfLastTag) : [];

  // Change page
  const paginate = (pageNumber) => {
    setCurrentPage(pageNumber);
  };

  const handleChangeInput = useCallback(
    (e) => {
      const inputValue = e.target.value;
      setInputValue(inputValue);
      // Get the filtered tags array
      const filteredTags = tags.filter((tag) => {
        const words = inputValue.toLowerCase().split(" ");
        return words.every((word) => {
          return tag.name.toLowerCase().includes(word);
        });
      });

      setTags(filteredTags);
    },
    [setInputValue]
  );
  useEffect(() => {
    const delayDebounceFn = setTimeout(() => {
      const fetchData = async () => {
        const result = await axios.get("http://ec2-3-34-134-67.ap-northeast-2.compute.amazonaws.com:8080/stackOverflow/tags",{},{withCredentials:true});
        setTags(result.data);
      };
      fetchData();
    }, 1000);

    return () => clearTimeout(delayDebounceFn);
  }, [inputValue]);
  console.log(tags);

  return (
    <Layout>
      <HeadContainer>
        <div className="header-content">Tags</div>
        <div className="main-content">
          A tag is a keyword or label that categorizes your question with other,
          similar questions.<br></br> Using the right tags makes it easier for
          others to find and answer question.
        </div>
        <input
          type="text"
          placeholder="Filter by tag name"
          onChange={handleChangeInput}
          value={inputValue}
          autoFocus
        />
      {tags !== null && (
                  <div className="tag-container">
                    {Array.isArray(currentTags) &&
                      currentTags.map((el) => <Tag key={el.id} tag={el} />)}
                  </div>
                )}
        <div>
          {tags.length > tagsPerPage && (
            <Pagination
              tagsPerPage={tagsPerPage}
              totalTags={tags.length}
              paginate={paginate}
              currentPage={currentPage}
            />
          )}
        </div>
      </HeadContainer>
    </Layout>
  );
};

export default Tags;
//Pagination.js
const Pagination = ({ tagsPerPage, totalTags, paginate, currentPage }) => {
  const pageNumbers = [];

  for (let i = 1; i <= Math.ceil(totalTags / tagsPerPage); i++) {
    pageNumbers.push(i);
  }

  // 현재 페이지가 속한 페이지 그룹 구하기
  const currentGroup = Math.ceil(currentPage / 5);

  // 페이지 그룹의 시작 페이지 번호 구하기
  const startPage = (currentGroup - 1) * 5 + 1;

  // 페이지 그룹의 끝 페이지 번호 구하기
  const endPage =
    startPage + 4 > pageNumbers.length ? pageNumbers.length : startPage + 4;

  // 이전 페이지 버튼 클릭 이벤트
  const handlePrevClick = () => {
    if (currentPage > 1) {
      paginate(currentPage - 1);
    }
  };

  // 다음 페이지 버튼 클릭 이벤트
  const handleNextClick = () => {
    if (currentPage < Math.ceil(totalTags / tagsPerPage)) {
      paginate(currentPage + 1);
    }
  };

  return (
    <PaginationContainer>
      <button onClick={handlePrevClick} disabled={currentPage <= 1}>
        이전
      </button>
      {pageNumbers.slice(startPage - 1, endPage).map((number) => (
        <button
          key={number}
          onClick={() => paginate(number)}
          className={currentPage === number ? "active" : ""}
        >
          {number}
        </button>
      ))}
      <button
        onClick={handleNextClick}
        disabled={currentPage >= Math.ceil(totalTags / tagsPerPage)}
      >
        다음
      </button>
    </PaginationContainer>
  );
};

export default Pagination;

페이지네이션도 라이브러리를 사용할 수 있었지만, 한 번쯤은 직접 만들어 보고싶어서 욕심냈던

부분이었다.

이렇게해서 내가 맡은 부분은 마무리 되었다!

모두 잘 작동되는 것을 확인하고, 서버와 맞춰보려고 했는데......

백엔드와의 협업이 처음인지라 연동부분에서 제대로 해결이 되지 않았다.

프리프로젝트의 마무리 하루 전쯤에 프론트엔드와 백엔드의 연동을 맞춰보는 날이었는데,

연동이 처음이다보니 만들어둔 dummyData를 서버 url로 바꾸어도 해결되지 않는 부분이 많았고,

왜 안되지? 싶은 부분들이 너무 많았다.

서버에서 내려주는 값과 우리가 받아오는 request - response값이 일치하지 않아서 다시 url을

고치기도 몇 번.. 협업이 처음이다보니 다들 어디서 문제인지 감이 오지 않았고,

ci/cd를 구축하지 않다보니 코드 수정 후 build와 배포를 반복적으로 하는 과정도 불편했다.

지금 생각해보면, api명세서를 받은 후 목업서버라도 빨리 연동시켜보는 작업이 우선시 되었어야

하는게 아닐까 싶다.

결국 코드는 다 완성했지만 연동부분에서 시간이 너무 오래걸려 마무리 되지 못하고 메인프로젝트로

넘어가게되었다.

아쉬운 부분이 있었던 pre-project였지만, 여기에서 내가 무엇이 부족한지 잘 알 수 있었던 기회

였다.

솔로프로젝트만 연이어 하다보면, 어떤점이 부족한지 잘 몰랐을 것이다.

하지만 이번 기회로 나를 더 알고, 메인 프로젝트에서는 내가 잘 할 수 있는 부분을 마음먹게 된 계기가

되었다.

2편으로 메인 프로젝트편으로 이어집니다!!

profile
진화중인 돌리입니다 :>

0개의 댓글