wecode 1차 프로젝트 : Tesla

유휘찬·2020년 8월 30일
1
post-thumbnail
post-custom-banner

Wecode 1차 프로젝트

😄 프로젝트 소개

  • 흔히 전기차 브랜드로 알려진 Tesla 사이트 클론 코딩

📅 개발 기간

  • 2020.08.18 ~ 2020.08.28

👱‍♂️ 팀원 구성

  • FE: 11기 유휘찬, 11기 오상구, 11기 최예흠
  • BE: 11기 김태수, 11기 문태기

🛠 기술 스택 및 구현 기능

기술 스택

  • React.js
  • React Router
  • Sass
  • AWS

구현 기능

나는 회원가입, 로그인, 메인페이지를 담당했다.

  1. 회원가입, 로그인 페이지✅
  • 계정 생성 정보 입력란 양식 확인 기능
  • local Storage 를 활용한 로그인 기능
  • 비밀번호 확인 기능
  1. 메인 페이지✅
  • 화면 길이에 따른 navigation bar on/off
  • 메인 화면 줌인 효과
  • 아이콘 클릭시 부드럽게 나타나는 subMenu
  • 버튼 클릭에 따라 화면의 다른 부분으로 줌 이동 및 다른 버튼 구현
  • navigation bar '맨위로' 버튼 구현
  1. 상세 페이지
  • 숫자 증가효과 구현
  • side bar 구현 및 해당 버튼 클릭시 해당 파트로 스크롤
  • 옵션에 따라 다른 차량정보 표시
  1. 주문 페이지
  • 옵션에 따라 다른 가격정보 표시
  • 차량 색상 선택 및 미리보기 기능
  • 선택한 옵션 결제창에 적용
  • 예상 결제가격 modal 창 구현

기억에 남는 코드

회원가입

개인적으로 기억에 남는 코드는 회원가입과 로그인 그리고 메인페이지에서 버튼을 클릭할 때마다 backgroundPosition 을 다르게 한 기능을 꼽고 싶다.

세션 때 백엔드분들과 잠깐 붙어보면서 로그인 기능이라는 것이 어떤 것인 줄은 알고 있었지만, 실제로 로직을 짜고 localStorage 에 access_token 이 존재하는지의 유무에 따라 로그인을 가능하게 하고, 다른 화면을 보여주는 것을 실제로 구현하는데 너무 즐거움이 있었다.

  createAccount = (e) => {
    const { last_name, first_name, email, password, isChecked } = this.state;
    e.preventDefault();

    if (!last_name) return alert("성에는 글자만 포함될 수 있습니다.");
    if (!first_name) return alert("이름에는 글자만 포함될 수 있습니다.");
    if (!email) return alert("유효한 이메일 주소를 입력해야 합니다.");
    if (!email.includes("@"))
      return alert("이메일 주소에 '@'를 포함해 주세요.");
    if (!password) return alert("비밀번호가 필요합니다.");
    if (
      !(
        password.length >= 8 &&
        password.match(/^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$/)
      )
    ) {
      return alert(
        "최소 8자 이상의 유효한 비밀번호를 입력하시기 바랍니다. 비밀번호에는 최소 1개의 숫자와 1개의 문자가 포함되어야 합니다."
      );
    }
    if (isChecked === false)
      return alert("계속하려면 개인 정보 공지 및 이용 약관에 동의해야 합니다.");
    else {
      fetch(`${API}/user/signup`, {
        method: "POST",
        body: JSON.stringify({
          email,
          password,
          first_name,
          last_name,
        }),
      })
        .then((res) => res.json())
        .then((res) => {
          if (res.message === "SUCCESS") {
            fetch(`${API}/user/signin`, {
              method: "POST",
              body: JSON.stringify({
                email,
                password,
              }),
            })
              .then((res) => res.json())
              .then((res) => {
                if (res.access_token) {
                  localStorage.setItem("access_token", res.access_token);
                  this.props.history.push("/");
                }
              });
          }
        });
    }
  };

처음에는 fetch 함수를 먼저 실행시킨 후 조건이 맞을 때만 회원가입을 가능하게 했는데 이 경우, 만약 조건이 맞지 않다면 기존에 입력했던 정보들을 기억하지 못하고 다시 새로고침을 해야만 했다. 그래서 애초에 조건이 맞을 경우에면 fetch 함수를 실행시킬 수 있도록 로직을 변경했다.

그리고 원래 테슬라 사이트는 회원가입이 되자마자 로그인이 되어 마이페이지로 넘어가게 되는데 시간관계상 마이페이지 까지는 구현을 하지 못했고, 로그인이 되어 localStorage 에 access_token 이 존재한다면 곧바로 로그인이 된 상태로 메인페이지로 넘어가게 했다.

리팩토링 과정 중에 객체의 key 와 value 의 변수명이 같으면 단축 속성명(객체 초기자)을 활용하여 간단하게 적을수 있다는 점도 배웠는데 매번 리팩토링의 중요성을 깨닫는다.

        body: JSON.stringify({
          email,
          password,
          first_name,
          last_name,
        }),

배웠던 것을 실제로 프로젝트에 적용시켜 보니 이제서야 뿌듯함이 느껴졌다.

메인페이지 화면이동 버튼

이 로직을 구현하는데 분명히 어려움이 있었고, 많은 고민을 한 결과물이라 매우 뿌듯했다. 테슬라의 메인페이지는(부득이하게도 프로젝트가 끝나는 날 테슬라 홈페이지가 변경되었다) 버튼을 클릭하면 화면 내에서 이미지 position 변경되면서 움직이는 효과가 있었다. 처음에는 감조차 오지 않았고, 버튼 클릭시 추가되는 사항을 일일이 조건문에 걸기를 시작했다. 하지만 이런 방식으로 하면 단 3개의 버튼일 뿐인데도 머리가 매우 복잡해지는 결과를 낳았다.

const modelsData = {
  model3: {
    title: "Model 3",
    backgroundPosition: "50%",
    storeBtn: false,
    btnColorS: "",
    btnBorderColorS: "",
    btnColor3: "white",
    btnBorderColor3: "white",
    btnColorX: "",
    btnBorderColorX: "",
  },
  modelS: {
    title: "Model S",
    backgroundPosition: "0%",
    storeBtn: true,
    btnColorS: "white",
    btnBorderColorS: "white",
    btnColor3: "",
    btnBorderColor3: "",
    btnColorX: "",
    btnBorderColorX: "",
  },
  modelX: {
    title: "Model X",
    backgroundPosition: "100%",
    storeBtn: true,
    btnColorS: "",
    btnBorderColorS: "",
    btnColor3: "",
    btnBorderColor3: "",
    btnColorX: "white",
    btnBorderColorX: "white",
  },
};

export default modelsData;

이렇게 해당 내용을 적용시킬 파일 옆에 관련 속성들을 담고 있는 객체를 선언해둔 뒤 원래 파일에서 import 받아 변수명으로 로직을 작성했더니 처음 작성했을 때보다 아주 훠얼씬 가독성이좋은 코드가 탄생했다.😁

  viewChangeEffect = (e) => {
    const { className } = e.target;
    if (className === "model3") this.setState(modelsData.model3);
    if (className === "modelS") this.setState(modelsData.modelS);
    if (className === "modelX") this.setState(modelsData.modelX);
  };
<li
  className="modelS"
  onClick={viewChangeEffect}
  style={{
    backgroundColor: btnColorS,
    border: btnBorderColorS,
  }}
/>
<li
  className="model3"
  onClick={viewChangeEffect}
  style={{
    backgroundColor: btnColor3,
    border: btnBorderColor3,
  }}
/>
<li
  className="modelX"
  onClick={viewChangeEffect}
  style={{
    backgroundColor: btnColorX,
    border: btnBorderColorX,
  }}
/>

후기

팀으로 하는 프로젝트이기 때문에 팀원분들께 정말 도움이 되고 싶었다. 그래서 일부러라도 더 많은 시간을 할애하려 애썼다. 개인적인 결론이지만 최소한 나의 할당량은 잘 해낸 것 같아 뿌듯하다. 프로젝트를 하면서 배운 점이 참 많다. 직접 배우진 않았지만 배웠던 것을 응용하고 구글링 해 가면서 기능을 구현하는 과정이 살짝 고통스러웠지만 결국 해내는 순간 지극히 행복했다.😎

익숙하지 않았던 git 의 flow 도 모두 외워버렸고, 이제는 이해하는 수준까지 왔다. 역시 자꾸 해봐야 느는 것 같다.

아쉬운 점

협업 중에 conflict 가 몇번 났었는데, 당시에는 "충돌? 해결하면 되지!!" 라는 생각을 가지고 있었지만 결국 충돌이 났다는 것은 작업중 변경 내용을 팀원분들과 그때그때 소통하지 않았다는 것을 의미한다는 생각이 들었다. 역시 프로그래밍은 소통이라는 생각이 많이 들었다. 그러므로 다음 프로젝트 때에는 누군가의 작업내용이 merge 되었을 때, 이를 꼭 알리고 어떤 내용이 바뀌었는지를 서로가 알 수 있게 해야한다!!

개인적인 아쉬움이 있다면, 화면 내에서 ref 를 사용하여 스크롤 이벤트가 발생하면 target ref 로 정확하게 이동하는 기능을 구현하고 싶었지만 어려운 내용이었고 시간도 부족해서 적용시키지 못했다. 이 부분은 꼭 따로 공부하리라!!

profile
tenacity
post-custom-banner

0개의 댓글