디즈니샵
https://www.shopdisney.com/
제품 카테고리를 줄이고 기능적인 측면을 구현하는데에 집중하기로 하였으며, 자세한 내용은 하기와 같습니다.
7개 카테고리와 3개 브랜드로 축소 구현
기획전 배너 2개, 추천상품 영역 1개
제품탐색(필터링,검색) - 찜하기 - 장바구니 넣기 - 결제
의사결정록 notion 도입
특정 안건 열람이 어려운 standing회의록의 단점 보완하고자 의사결정록 도입.
이슈를 한눈에 열람하고 구성원간 공유 원활히 할 수 있도록 함.
trello + BigPicture
트렐로 카드는 개별 업무단위를, BigPicture는 전체 진도율 관리.
크게 3가지 단위와 추가구현기능으로 업무를 나누었고,
붉은 테두리의 영역을 맡아 구현하기로 함.
제품데이터를 사전에 픽스함으로써 기능의 범위가 명확해졌으며, Backend와의 소통 원활해짐. 아울러 프로젝트 막바지에 신경쓰기 어려운 이미지작업을 사전에 마쳐놓음으로써 팀원들이 개발에만 전념할 수 있는 환경 조성
GIT : https://github.com/JaySurplusYoon/31-1st-kidsney-frontend
필터
, 가격순정렬
, 검색
, 페이지네이션
4가지로 구분.useLocation
에서 url
을 받아 렌더링하는 방법 사용할 수 없음.state
에 저장하여 렌더링의 대상이 되는 queryString
으로 만들어 렌더링하는 방식으로 구현함.(1) Product List에서는 Filter, Sorter, Search, Pagination에 필요한 state
와 이를 수정할 수 있는 function
을 만들어 각각의 컴포넌트로 전달.
const handleFilter = (name, attr) => {
const filterArr = [...filters];
filterArr.includes(`${name},${attr}`)
? filterArr.splice(filterArr.indexOf(`${name},${attr}`), 1)
: filterArr.push(`${name},${attr}`);
setFilters(filterArr);
setQueryStrings(filterArr);
};
※필터의 경우 1회 클릭시 적용, 중복 클릭시 적용이 해제되므로, Splice로 중복된 인덱스의 필터배열을 제거하도록 함.
(2)각각의 컴포넌트에서는 onClick
, onChange
등을 통해 내려받은 function
으로 부모의 state
를 수정하고 끌어올림.
<li
key={categoryAttr}
className="categoryAttr"
onClick={() => handleFilter(categoryName, categoryAttr)}
>
(3)끌어올린 state
값으로 queryParameter
를 만들고 이에 의존성에 있는 useEffect
내부의 fetch
함수로 화면을 렌더링.
switch (splittedFilter[0]) {
case 'sub':
addParamFilters.push(`&sub=${param}-${splittedFilter[1]}`);
break;
case 'size':
addParamFilters.push(`&size=${splittedFilter[1]}`);
break;
case 'character':
addParamFilters.push(`&character=${splittedFilter[1]}`);
break;
default:
}
(1)배송정보 유효성 검사 후, 고객이 입력한 주소를 기본배송지로 업데이트하겠다는 의사를 확인하고 이에 따라 결제대금 차감 및 주소 업데이트 진행.
const submitOrder = () => {
if (orderNecessaryInfo) {
if (orderInfo.updateAddress) {
postBalance();
patchAddress();
} else {
postBalance();
}
} else alert('정보를 모두 입력해주세요');
};
(2)결제는 POST방식으로 서버와 통신하여 진행하며 처리결과는 alert
로 안내.
const postBalance = () => {
fetch(`${BASE_URL}/orders`, {
method: 'POST',
headers: {
Authorization: localStorage.getItem('token'),
},
body: JSON.stringify({
total_price: subtotal,
}),
})
.then(response => {
if (response.ok) {
alert('주문이 완료되었습니다.');
} else if (response.message === 'moneyless') {
alert('잔액이 부족합니다.');
} else if (response.message === 'stockless') {
alert('재고가 부족합니다.');
} else {
throw new Error('Unexpected Error');
}
})
.catch(error => {
// eslint-disable-next-line no-console
console.log(error.message);
});
};
(3)주소 업데이트는 PATCH방식으로 서버와 통신하여 진행하며 처리결과는 alert
로 안내.
const patchAddress = () => {
fetch(`${BASE_URL}/users/`, {
method: 'PATCH',
headers: {
Authorization: localStorage.getItem('token'),
},
body: JSON.stringify({
zip_code: orderInfo.zipCode,
location: orderInfo.addressMain,
datail_address: orderInfo.addressDetail,
}),
})
.then(response => {
if (response.ok) {
alert('주소변경이 완료되었습니다.');
} else {
throw new Error('Unexpected Error');
}
})
.catch(error => {
// eslint-disable-next-line no-console
console.log(error.message);
});
};