[PiaSpace] INTERNSHIP Project

younghyun·2022년 4월 16일
0

회사 소개

산업 분석 관련 인강 스트리밍 + 스트리밍 기반의 커뮤니티 운영

잘한점

따로 Front를 하는 분이 없고, 혼자 모든 걸 해결해야 했기에 구글링 및 고민하는 시간을 많이 가질 수 있었고, 그 과정에서 시간을 투자하면 구현할 수 있다는 것에서 자신감을 얻게 되었다.

아쉬운점

자료구조, 언어, 라이브러리등 지식 부족이 blocker로 다가왔고, 그로 인해 프로젝트 일정에 맞춰서 구현하는 점이 어려웠다. 공부함에 따라 점차 해결할 될 것이라고 생각한다. 특히 자료구조에 따라 코드가 간결해질 수 있음을 느낄 수 있었던 것은 큰 깨달음 이었다.

기타

피아스페이스에서 현재 진행하고 있는 산업분석 콘텐츠 외에 개발자 교육 과정 콘텐츠에 대한 아이디어를 각자 준비하여 서로 발표하고 의견을 나누는 시간을 가졌고, 실제 서비스를 기획하는 과정의 일부를 참여할 수 있어 실제 초기 스타트 업 사업 기획, 업무 스타일을 배울 수 있어서 좋았다.
데일리 스탠드업 미팅, 중간점검회의, 주간점검회의로 기획팀 및 개발팀의 작업진행상황의 원활한 업무 공유가 이루어졌기에, 기획에 따라 빠르게 개발 작업 상황을 변경할 수 있어서 좋았다.

구현 화면, 코드


  • oneButton 정렬
   let sortKey = '';
   let ascOrder = true;
  
   const sortedUsersData = key => {
      if (sortKey === key.sort) {
        ascOrder = !ascOrder;
      } else {
        sortKey = key.sort;
        ascOrder = true;
      }

      let sortStr = sortKey + (ascOrder ? '_ascending' : '_descending');
      console.log(sortStr);

      setSortString(sortStr);
    };
    
-> sortedUsersData 함수가 호출 될 때마다 백엔드로nickname_ascending, nickname_descending 등으로 값이 바뀌면서 넘어감. 처음에는 메서드와, state를 많이 사용했으나 리팩토링을 거치면서 코드가 간결해짐.
  • 컴포넌트 재 사용, 자료구조
const [currentClass, setCurrentClass] = useState(null);

<div className="seriesManage" onClick={e => clickHandler(e)}>
 시리즈 관리
</div>

const clickHandler = e => {
    setCurrentClass(e.target.className);
  };
  

<div className="userSeriesTableContent">
  {currentClass ? USER_SERIES_TABLE[currentClass] : <UserSeriesTable />}
</div>

const MEMBER_DATA_TITLE = [{ title: '회원' }];

const MEMBER_FILTER_SEARCH_DATA = [
  { id: 1, filterData: '회원유형(전체)' },
  { id: 2, filterData: 'Google' },
  { id: 3, filterData: 'Pia' },
  ...
  { id: 7, filterData: '구분(전체)' },
  { id: 8, filterData: '관리자' },
  { id: 9, filterData: '무료회원' },
  ...
  { id: 11, filterData: '스트리밍 구독(전체)' },
  { id: 12, filterData: 'True' },
  { id: 13, filterData: 'False' },
  { id: 14, filterData: '아이디' },
  { id: 15, filterData: '닉네임' },
  { id: 16, filterData: '이메일' },
  ...
];

const MEMBER_DATA_TABLE_TITLE = [
  { id: 1, title: 'No.' },
  { id: 2, title: '회원유형' },
  { id: 3, title: '아이디' },
  { id: 4, title: '닉네임', sort: 'nickname' },
  { id: 5, title: '구분' },
  { id: 6, title: '스트리밍 구독' },
  ...
];


const USER_SERIES_TABLE = {
  userManage: (
    <UserSeriesTable
      title={MEMBER_DATA_TITLE}
      tableTitleData={MEMBER_DATA_TABLE_TITLE}
      filterSearch={MEMBER_FILTER_SEARCH_DATA}
    />
  ),
  seriesManage: (
    <UserSeriesTable
      title={SERIES_DATA_TITLE}
      tableTitleData={SERIES_DATA_TABLE_TITLE}
    />
  ),
};


위와 같이 할 경우 페이지별 다르게 키 값을 주는 점에서 문제가 생겼음. 
테이블 구조에 colgroup을 사용하기 위해서는 키, 값이 하나로 지정이 되어야 했음.
따라서, 해당 페이지 내에서 키 값을 정의해서 TableList컴포넌트에 props로 값을 내려주는 구조로 수정함.

-- userList컴포넌트 -- 

const MEMBER_DATA_TABLE_TITLE = [
    { id: 1, title: 'No.', key: 'id', width: '3%' },

<div className="userList">
      <Menu />
      <TableList
        title={MEMBER_DATA_TITLE}
        tableTitle={MEMBER_DATA_TABLE_TITLE}
        data={users}
        arrNum={arrNum}
        updateOffset={updateOffset}
        listFilterLimit={listFilterLimit}
        typeFilter={typeFilter}
        userTypeFilter={userTypeFilter}
        subscriptionFilter={subscriptionFilter}
        searchBoxFilter={searchBoxFilter}
        updateUserInput={updateUserInput}
        sortedUsersData={sortedUsersData}
        platformData={MEMBER_PLATFORM_DATA}
        userTypeData={MEMBER_USERTYPE_DATA}
        subscriptionPlanData={MEMBER_SUBSCRIPTION_PLAN_DATA}
        searchData={MEMBER_SEARCH_DATA}
      />
</div>

-- TableList 컴포넌트 --
let newData = data.slice(0, data.length - 1);

<colgroup>
 {tableTitle.map((t, idx) => {
  return <col width={t.width} key={idx} />;
 })}
</colgroup>
<tbody>
 {newData.map((content, idx) => {
  return (
   <tr className="table_body" key={idx}>
    {tableTitle.map((t, idx) => {
     return (
      <td className="table_body_col" key={idx}>
        {content[t.key]}
      </td>
     );
    })}
   </tr>
  );
 })}
</tbody>
-->
처음에는 본문만을 위한 컴포넌트를 별도로 생성함. 하지만 colgroup을 사용하기 위해서는 한 컴포넌트 안에 제목과 내용이 있어야 했고, 그러기 위해서는 본문 내용이 props로 내려온뒤 data라는 하나의 state에 배열 형태로 저장되는 구조가 되어야 했음. 그 후 제목의 개수에 맞게 본문의 내용이 나오는 구조로 만듦.
  • 중복 Pagination
-- 각 페이지 컴포넌트 구조 -- 
const arrNum = [10, 20];
 
const updateOffset = buttonIndex => {
    setPage(buttonIndex);
  };

const listFilterLimit = e => {
    setLimit(e.target.value);
  };
  
-- TableList 컴포넌트 구조 --

<select className="courseSelector6" onChange={listFilterLimit}>
 {arrNum.map((com, idx) => (
  <option value={com} key={idx}>
   {com}개
  </option>
))}
</select>

<div className="userSeriesTableItems">
 <Buttons updateOffset={updateOffset} />
</div>

-- Buttons 컴포넌트 --
const [page, setPage] = useState(0);

const prevButton = () => {
  if (page >= 5) {
    setPage(page - 5);
  }
};

const nextButton = () => {
  setPage(page + 5);
};

<div className="pageBtn">
      <button onClick={() => prevButton()}>{'<'}</button>
      <button onClick={() => updateOffset(0 + page)}>{1 + page}</button>
      <button onClick={() => updateOffset(1 + page)}>{2 + page}</button>
      <button onClick={() => updateOffset(2 + page)}>{3 + page}</button>
      <button onClick={() => updateOffset(3 + page)}>{4 + page}</button>
      <button onClick={() => updateOffset(4 + page)}>{5 + page}</button>
      <button onClick={() => nextButton()}>{'>'}</button>
</div>

--> listFilterLimit함수를 통해 10, 20의 limit값 선정. updateOffset함수 실행을 통해 page값 1, 2, 3, 4, 5를 백 엔드로 넘겨줌.
  • 필터 기능
const typeFilter = e => {
    setPlatform(e.target.value);
  };

const userTypeFilter = e => {
    setUserType(e.target.value);
  };

const subscriptionFilter = e => {
    setSubscriptionPlan(e.target.value);
  };
  
<select
className="userSeriesTableFilterBoxOne"
onChange={typeFilter}
>

<select
className="userSeriesTableFilterBoxTwo"
onChange={userTypeFilter}
>

<select
className="userSeriesTableFilterBoxThree"
onChange={subscriptionFilter}
>
--> 회원 유형, 구분(관리자, 유료 회원), 구독 여부에 따라 필터 기능 구현.
  • 검색 기능
-- 각 페이지 컴포넌트 -- 
const searchBoxFilter = e => {
  setSearchBoxLock(e.target.value);
};

const updateUserInput = e => {
  let userInput = e.target.value;
  setSearchUsersData(userInput);
};

-- TableList 컴포넌트 -- 
<select
 className="userSeriesTableSearchBoxOne"
 onChange={searchBoxFilter}
>
{searchData.map((data, idx) => (
 <option value={data.serverData} key={idx}>
  {data.filterData}
 </option>
))}
</select>

<SearchBox handleChange={updateUserInput} />
--> 필터를 통해 닉네임, 아이디 등 검색할 수 있는 카테고리 제한을 줌.
updateUserInput함수를 통해 입력 창에 검색할 값 입력.
  • NavBar 기능
-- Menu 컴포넌트 --
const [streamingVisible, setStreamingVisible] = useState(true);

<div
 className="streamingManageTitle"
 onClick={() => {
 setStreamingVisible(!streamingVisible);
 }}
>
 <div className="streamingManage">스트리밍 관리</div>
 <img className="downArrow" alt="arrow" src={Arrow} />
</div>
{streamingVisible && (
 <div className="streamingManageWrap">
  <div
   className="seriesManage"
   onClick={() => navigate('/AdminSeriesList')}
  >
  시리즈 관리
 </div>
 <div className="shortVideoManage">단편 영상 관리</div>
</div>
)}
--> onClick이벤트가 일어날 때 마다 boolean타입 변경을 통해 일부
메뉴를 보이게 하거나 안 보이게 함.

앞으로 다짐

모든 문제에는 답이 있다. 안 되면 될 때까지.

profile
선명한 기억보다 흐릿한 메모

0개의 댓글