TOWESTORY 1차 프로젝트 회고

김형석·2022년 6월 5일
1

WECODE

목록 보기
24/33
post-thumbnail

프로젝트 소개

  • 상품 캐릭터 브랜드 이커머스 사이트 무직타이거를 모티브로 한 프로젝트
  • 사이트: 무직타이거 (https://www.muziktiger.com/)
  • 기간: 2022년 05월 23일 (월) - 06월 03일 (금) (2주)
  • 개발인원 : 5 Front-end, 2 Back-end
  • Front-end Github
  • Back-end Github

    무직타이거는 캐릭터 브랜드 상품을 파는 커머셜 사이트로, 학습 목적이지만 상품 이미지를 마음대로 사용할 수가 없어, UI 레이아웃은 비슷하게 사용하며 새로운 장난감 커머셜 사이트로 바꾸어 프로젝트를 진행하였다.

데모 영상

구현 항목

필수구현

회원가입 / 로그인, 메인페이지, 상품 리스트, 상품 상세, 장바구니, Nav / Footer, 마이페이지

추가 구현

베스트10, 주문하기(포인트결제), 리뷰 / 게시판, Nav 검색기능

기술 스택

Front-end

: HTML/CSS, JavaScript, React.js, React-Router, Sass

Back-end

: Python, Django

협업도구

Trello

  • 팀원간 프로젝트 협업도구로는 Trello와 Slack을 활용했다.

내가 맡은 부분

list 페이지는 기본 데모 영상에서 가져왔고, navbar는 따로 서버없이 영상을 찍었다.

검색기능

  const searchBtn = e => {
    e.preventDefault();
    const string = `/itemList?category=&search=${e.target.search.value}`;
    navigate(string);
    e.target.search.value = '';
  };

검색기능은 쿼리 스트링(Query String)을 사용하여 말 그대로 해당 엔드포인트에 대해 질의문(query)를 보내는 요청을 한 것이다. e.target으로 value을 가져와 쿼리 스트링에 동적으로 값을 넣어주었다.
이 부분은 제품 리스트에서 더욱 다양하게 사용하고있기 때문에 밑에서 적어보도록하자.

//상수데이터
const NAV_TITLES = [
  {
    id: 0,
    title: 'TOWE STORY',
    category: ['BRAND', 'CHARACTER', 'OURSTORY'],
  },
  {
    id: 1,
    title: 'STORE',
    category: ['CAR', 'LEGO', 'DOLL', 'PUZZLE', 'ALL', 'BEST\n10'],
  },
  { id: 2, title: 'BOARD', category: ['Q&A', 'BOARD'] },
  { id: 3, title: 'GALLERY', category: ['GALLERY'] },
];

//컴포넌트
const NavMenu = ({ navTitle, navId, hoverOn }) => {
  const { id, title, category } = navTitle;

  return (
    <li
      className="navbarMenuItem"
      onMouseEnter={() => {
        hoverOn(id);
      }}
    >
      {title}
      <div className="bottomLine" />
      <ul className="dropBoxs">
        {navId === id &&
          category.map((category, i) => (
            <Dropbox category={category} key={i} />
          ))}
      </ul>
    </li>
  );
};

navbar는 처음에 다른 팀원이 맡았는데 제품 리스트 페이지가 생각보다 일찍 마무리가 되어서 넘겨 받아 만들기 시작했다.
navbar 드랍박스의 내부 내용도 변하지 않기 때문에 상수 데이터를 사용하여 map으로 돌려주었다.
navbar를 2주차에 들어가게 되어, 먼저 navbar를 완성한 다른 팀한테 map을 여러번 돌려야한다는 꿀팁을 듣게 되었고, mapping 로직을 짜는데에 있어서 많은 도움을 얻을 수 있었다.
회고록을 쓰며 발견했는데, 상수데이터 category(key)안에 배열 객체를 만들어 각각의 category에 id값을 따로 주는 것이 맞겠다.

토큰 사용

  const goTomypage = () => {
    localStorage.getItem('token')
      ? fetch(`${API.users}`, {
          method: 'GET',
          headers: {
            Authorization: localStorage.getItem('token'),
          },
        })
          .then(res => {
            if (res.ok) {
              return res.json();
            }
          })
          .then(() => {
            navigate(`/mypage`);
          })
      : navigate(`/login`);
  };

토큰 사용은 로그인, 회원가입, 마이페이지에서 사용하고 있어 내가 맡은 페이지에서는 쓸 일이 없다고 생각했지만... navbar에 로그인 전 후로 달라지는 기능이 필요했다.
토큰을 통하여 서버와 통신을 하는 것이 신기하고 재미있어 간단하게 회고록에 작성하기로 했다.
localStorage의 토큰을 서버에 보내 그 토큰에 맞는 유저 정보를 받는 것이었다.

Item List

Query String

백앤드에서 필터, 정렬, 페이지네이션 기능을 구현할 수 있는지 몰랐었다... 필터기능 정렬기능을 다 구현한 후에 알게 되어 코드를 다 지우게 되었다.
백앤드에서 정리를 해서 데이터를 보낸다고 하면 List 페이지는 프론트가 할 게 없다고 생각했지만 오산이었다.
멘토님들에게도 많은 질문을 하였고, 많은 시간을 쏟아서 구현은 해내었지만 더 공부해서 클린하게 바꾸어야 한다고 생각한다.

  const [filterValue, setFilterValue] = useState({
    categoryValue: '',
    sortValue: '',
    offValue: '',
  });

//categoryValue
  const onCategory = name => {
    setFilterValue(prev => {
      return { ...prev, sortValue: '' };
    });
    setFilterValue(prev => {
      return { ...prev, offValue: `` };
    });
    const lowerValue = name.toLowerCase();
    setFilterValue(prev => {
      return { ...prev, categoryValue: lowerValue };
    });
    setQuery(9);
    setSortColor('');
  };

//offValue
  const getBynIndex = () => {
    setQuery(query => query + 3);
    const limit = query;
    const offset = 0;
    const queryString = `&offset=${offset}&limit=${limit}`;
    setFilterValue(prev => {
      return { ...prev, offValue: queryString };
    });
  };

//sortValue
  const onSort = value => {
    setFilterValue(prev => {
      return { ...prev, sortValue: value };
    });
  };
  
useEffect(() => {
   const queryString = `?${
      filterValue.categoryValue
        ? `${
            filterValue.categoryValue === `all`
              ? ''
              : `category=${filterValue.categoryValue}`
          }`
        : ''
    }${filterValue.sortValue ? `&sort=${filterValue.sortValue}` : ''}${
      filterValue.offValue ? `${filterValue.offValue}` : ''
    }`;
    if (
      filterValue.categoryValue ||
      filterValue.sortValue ||
      filterValue.offValue
    ) {
      navigate(queryString);
    }
  }, [filterValue]);

Query String 을 활용하여 API 값을 받아 온 것으로, 작성한 코드를 큰 틀로 풀어보자면 아래와 같다.

  • 생성한 state 를 변경하기 위하여 setState 를 각 드롭 다운 컴포넌트로 props 전달
  • 각 항목 버튼에 onClick 을 적용하여 함수 실행 시 value 값을 함수 선언식을 사용하여 string 형태로 setState에 저장
  • 최상위 컴포넌트에서 객체로 전달받은 value 값을 다중 쿼리문으로 작성
  • 작성된 다중 쿼리문을 useNavigate Hook 을 이용하여 전달
  • useLocation Hook 을 이용하여 전달된 쿼리문을 받아 url 작성
  • 작성된 url 을 useEffect Hook 과 fetch 함수를 사용하여 통신 진행

코드가 클린하지도 않고 완벽하지도 않지만, 프로젝트 중에 가장 뿌듯한 부분이었고 동시에 더 많은 공부가 필요하다는 생각이 들었던 시간이었다.

URLSearchParams

Query String으로 코드를 수정하다 보니 기존에 코드가 바뀌어 카테고리 필터를 클릭했을 때, 사용자가 지금 무슨 카테고리를 보고있는지 표시해주기가 어려웠다.
이 부분은 다른 팀의 list페이지를 맡은 분에게 물어 바로 수정할 수 있었고 유용하다고 생각하여 남겨보려고한다.
URLSearchParams를 사용한 것인데, URLSearchParams는 URL의 쿼리 문자열에 대해 작업할 수 있는 유틸리티 메서드를 정의하는 코드로 URLSearchParams.get() 함수를 통해 Query String의 특정 String 값을 사용할 수 있었다.

  let title = urlParams.get('category');

  return (
    <div className="listContainer">
      <div className="listTitle">{`${
        title === null ? 'ALL' : title.toUpperCase()
      }`}</div>
      <ProductCategory onCategory={onCategory} />

//...중략

위의 GIF에서 확인할 수 있듯이, URLSearchParams.get() 함수를 통해 필터 value값을 사용하여 현재 보고있는 카테고리를 확인할 수 있도록 했다.

잘한점 아쉬운점

잘한점과 아쉬운점을 이야기 하자면 많지만(물론 잘한점이 더 많다고 생각한다), 이번 프로젝트에서 PM을 맡게 되었기에 잘한점과 아쉬운점을 PM입장에서 적어보려고 한다.

잘한 점

잘한 점은 프론트앤드와 백앤드끼리의 소통이 잘 되었던 점이다. 기본적으로 아침 10시에 Stand-up Meeting을 진행하여, 서로의 진도 및 애로사항을 확인하였다. 또한 저녁 6시에도 간단히 Stand-up Meeting을 통하여 하루의 일과에 대해서 팀원끼리 공유를 하였다.
처음에는 하루에 2번이나 Meeting을 할 필요가 있을까 라는 생각을 하였지만, 서로가 오늘 무엇을 했는가에 대한 이야기를 하며, 응원을 하고 자극을 받았기 때문에 우리 팀이 성공적으로 프로젝트를 마칠 수 있었다고 생각한다.

아쉬운 점

아쉬운 점은 Trello 사용의 미숙함이었다. 내 생각에는 Trello 사용의 미숙함은 곧 프로젝트의 진행을 세세하고 계획적으로 이끌어 나가지 못한 것이라고 생각이 든다. 물론 우리 팀은 사전에 계획했던 필수 기능 구현을 다 하고 추가 기능 구현까지 진행을 하였지만, 지금 보면 그저 운이 좋았던 것이라고 생각한다.
팀플에 있어 전체적인 계획을 짜고, 그것을 토대로 팀끼리 소통을 하고 프로젝트를 진행하는 것에 대한 중요성을 정말 많이 느끼게 되었다.

마치며

일단 프로젝트 2주 동안 체력은 조금 힘들었지만, 이 부분 말고는 정말 힘들다고 생각한 적이 한 번도 없었다. 내가 PM이어서 그렇기도 하겠지만 팀원들끼리 팀워크도 매우 좋았고, 다들 열심히 프로젝트에 임해주어서 트러블이 생길 일도 없었다.
팀원들은 어떻게 느꼈을지 모르겠지만... 나는 팀플이 너무 재미있었고 프로젝트 기간에 위코드에 오는 것도 너무 즐거웠다. 팀원들도 즐거웠을거라고 믿는다.
물론 남은 2차 프로젝트도 1차처럼 재미있고 즐겁게 참여할 것이고, 마지막으로 2주 동안 함께 고생했던 우리 팀원들에게 고맙고 수고했다는 말을 꼭 하고 싶다. 2차때도 또 만납시다.

profile
블로그 이사 : https://hengxi.tistory.com

0개의 댓글