위코드에서 진행한 웹사이트 클론 프로젝트로 아이디어를 냈던 BEATS 홈페이지를 만들게 되었다 2주동안 백앤드1명 프론트3명이서 작업을 진행하였고 Trello 와 매일 아침 StandUP Meeting 을 하면서 작업을 이어나갔다
CRA, React Router, Sass, Fetch, Map 등을 사용하였고
Daum map api 와 react-reveal 라이브러리를 활용해서 스크롤 애니메이션을 구현하였다
제품 메인 리스트 부분과 제품의 상세 페이지, 제품 상세에서 장바구니 추가하는 부분, 구매페이지와 구매내역 확인 페이지를 작업하게 되었다
비츠의 제품 각각의 상세 페이지는 레이아웃이 조금씩 다 달랐다 그래서 초반에는 다 하려고 했는데 작업하다보니 한 페이지 만드는데도 시간이 엄청 걸렸다... 진짜로 눈 빠질뻔... 그래서 두개 정도만 다 작업하고 나머지는 8 페이지는 밑에 보이는 빌리 아일리시 사진 처럼 커버 부분만 작업했다 원 페이지 느낌으로! 이 부분도 백앤드의 데이터를 받아와서 작업했는데 제품별로 다른 페이지로 이동을 해야 했기 때문에 라우터를 이용해서 페이지를 이동했다 개인적으로 이부분이 제일 재밌었다!
버튼을 클릭 했을 때 각 제품의 id 를 가져와서 라우터에 적용해 이동하고 그 id 를 가진 데이터를 상세페이지 레이아웃에 뿌려주고 그 해당 페이지에서 컬러 선택 후 add to cart 를 누르면 컬러와 제품 아이디를 넣어 POST 로 서버에 전송하는 것 까지! 처음에는 너무 플로우가 복잡해서 힘들었지만 하다보니 너무 재밌었다 중간에 약간 멘붕이 오기는 했지만...🤦♀️
빌리 아일리시 사진이 너무 이뻐서 작업할 맛 났던 페이지
이 부분에 원래는 없던 color 선택 버튼을 추가했다 생각보다 잘 어울려서 놀람
전체 다 작업했던 PowerBeats 제품 상세 페이지
state = {
current: 0,
view: false,
};
const selProduct = {
0: {
productColor: "white",
productColorName: "White",
productColorNameC: "#000",
src: `${Config.ProductImage}/powerbeats-white.png.large.2x.png.large.2x.png`,
check: 1,
color: "rgb(101, 101, 101)",
},
1: {
productColor: "black",
productColorName: "Black",
productColorNameC: "#fff",
src: `${Config.ProductImage}/powerbeats-black.png.large.2x.png.large.2x.png`,
check: 1,
color: "#fff",
},
2: {
productColor: "#911827",
productColorName: "Red",
productColorNameC: "#fff",
src: `${Config.ProductImage}/powerbeats-red.png.large.2x.png.large.2x.png`,
check: 1,
color: "#fff",
},
};
// 이렇게 스타일을 리스트로 만들어서 접근했다
<section
className="mainContentsSelect"
id="color"
style={{
backgroundColor: selProduct[this.state.current].productColor,
}}
>
대충 이런 느낌..
product 를 누르면 리스트 페이지가 뜨고 그 하나하나의 리스트도 하나의 컴포넌트에 데이터를 map 돌려서 정보들을 보여준 것이고 그 안에 상세 페이지로 이동하는 버튼도 컴포넌트화 된 버튼이라 직접적으로 onclick을 넣을 수 없어 함수를 props 로 전달해서 사용했다 그래서 그 버튼을 누르면 각 제품별 api 를 받아와서 라우터 이동을 한다 그리고 나서 그 상세 페이지에서 add to cart 버튼을 누르면 그 정보를 서버로 넘겨주고 서버는 그 데이터를 가지고 있다가 장바구니를 누르면 다시 보내준다... 이 부분이 너무 복잡해서 이해하는데 힘들었고 그만큼 재미있었다
그러고나서 코드를 치는데 코드 자체는 생각보다 덜 복잡해서ㅋㅋㅋ 마음이 복잡해졌다😂
// Routes.js
// 라우터 이동 코드
<Route exact path="/product/:num" component={ProductDetails} />
// 각 카드에 버튼에 들어갈 함수
goDetail = () => {
this.props.history.push(`/product/${this.props.num}`);
};
// props 로 전달받은 데이터 map 돌려서 DetialCard 컴포넌트에 전달하는 코드
const detailList =
this.state.list &&
this.state.list.map((post, idx) => (
<DetailCard
key={idx}
id={post.id} // 중요한 id 값
name={post.name}
price={post.price}
image={post.imgage_url[0].imgage_url}
subject={post.subject[0].subject}
description={post.theme[0].description}
specLists={post.item_info}
color={post.colors}
/>
));
이 부분은 내가 코드를 짰지만 진짜 신기하다고 생각했다 선택한 컬러와 제품을 api 에 넣어서 서버로 전송하는 코드인데 진짜 데이터가 보내지고 저장되서 장바구니에 찍히는 걸 보니 뿌듯했다 다시한 번 고유한 id 값의 중요성?을 느꼈다
class DetailCard extends React.Component {
state = {
current: 0,
};
// order 버튼 눌렀을 때 각 제품의 아이디 값을 인자로 받아와서 fetch 함수 실행
sendProduct = (id) => {
const token = localStorage.getItem("Authorization");
// api 는 config 파일로 변수화 해서 사용하였고 해당 제품의 아이디와 컬러값을 넣어서 데이터를 전송하는 코드이다
fetch(`${API}/product/${id}/${this.state.current}/cart`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: token,
},
body: JSON.stringify({
text: "order",
}),
}).then((res) => {
if (res.status === 200) {
alert("Add to cart");
} else {
alert("try again");
}
});
};
// color 선택 함수 컬러를 선택했을 때 그 컬러의 id 를 state 의 current 값으로 넣어주었다
selectColor = (colorID) => {
this.setState({ current: colorID });
};
장바구니에서 order 버튼을 누르면 서버로 장바구니에 담겨있던 정보를 보내고 order 페이지로 이동 -> 서버에서 다시 그 정보를 받아서 뿌려줌 -> 최종 order 버튼을 누르면 서버로 정보를 전달 -> order confirm 페이지로 이동 -> 서버에서 다시 데이터를 받아와서 뿌려줌!
// 페이지가 처음 로드 될 때 디드 마운트로 정보를 받아오고 state 에 저장한다
componentDidMount() {
const token = localStorage.getItem("Authorization");
fetch(`${API}/cart`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: token,
},
})
.then((res) => res.json())
.then((res) =>
this.setState({
orderList: res.data[0].cart_data,
userInfo: res.data[0],
totalP: res.data[0].total_price,
})
);
}
// 최종 order 버튼 클릭시 서버로 데이터를 보낸다
orderHandler = () => {
const token = localStorage.getItem("Authorization");
fetch(`${API}/order`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: token,
},
body: JSON.stringify({
email: this.state.userInfo.email,
full_name: this.state.userInfo.full_name,
address: "address",
}),
}).then((res) => {
if (res.status === 200) {
alert("Order Completed");
this.props.history.push(`/order/confirm`);
} else {
alert("try again");
}
});
};
처음 주제 아이디어를 낼 때 아무래도 계속 디자인을 하던 사람이라 거의 디자인 중심으로 주제를 찾았다ㅠ 그래서 그런지 막상 시작하려고 페이지를 뜯어보니 비츠 페이지가 생각보다 페이지 수가 적었다 심지어 로그인 장바구니 등은 애플 사이트로 넘어가버리고... (팀원들에게 미안해지는 부분..)
그래서 우리는 가능한 한 모든 페이지를 구현기로 했다 원래는 없는 로그인, 회원가입, 장바구니, 주문 페이지를 추가하였다 로그인과 회원가입, 장바구니는 Asoap 페이지의 UI 를 가져와서 작업했고 구매 페이지는 Lush 에서 UI 를 가져왔다 이렇게 기획과 작업을 병행하다보니 프로젝트 시작 1주일은 UI에 잡혀있었다
하지만 우리 팀원들이 속도도 빠르고 시간 투자도 정말 많이 해서(맨날 12시 넘어서까지 남아있었다👽) 거의 일주일 안에 페이지 UI 가 끝나고 기능에 들어갈 수 있었다👏👏👏👏