산업 분석 관련 인강 스트리밍 + 스트리밍 기반의 커뮤니티 운영
따로 Front를 하는 분이 없고, 혼자 모든 걸 해결해야 했기에 구글링 및 고민하는 시간을 많이 가질 수 있었고, 그 과정에서 시간을 투자하면 구현할 수 있다는 것에서 자신감을 얻게 되었다.
자료구조, 언어, 라이브러리등 지식 부족이 blocker로 다가왔고, 그로 인해 프로젝트 일정에 맞춰서 구현하는 점이 어려웠다. 공부함에 따라 점차 해결할 될 것이라고 생각한다. 특히 자료구조에 따라 코드가 간결해질 수 있음을 느낄 수 있었던 것은 큰 깨달음 이었다.
피아스페이스에서 현재 진행하고 있는 산업분석 콘텐츠 외에 개발자 교육 과정 콘텐츠에 대한 아이디어를 각자 준비하여 서로 발표하고 의견을 나누는 시간을 가졌고, 실제 서비스를 기획하는 과정의 일부를 참여할 수 있어 실제 초기 스타트 업 사업 기획, 업무 스타일을 배울 수 있어서 좋았다.
데일리 스탠드업 미팅, 중간점검회의, 주간점검회의로 기획팀 및 개발팀의 작업진행상황의 원활한 업무 공유가 이루어졌기에, 기획에 따라 빠르게 개발 작업 상황을 변경할 수 있어서 좋았다.
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에 배열 형태로 저장되는 구조가 되어야 했음. 그 후 제목의 개수에 맞게 본문의 내용이 나오는 구조로 만듦.
-- 각 페이지 컴포넌트 구조 --
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함수를 통해 입력 창에 검색할 값 입력.
-- 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타입 변경을 통해 일부
메뉴를 보이게 하거나 안 보이게 함.
모든 문제에는 답이 있다. 안 되면 될 때까지.