엘리스 첫번째 웹 서비스 프로젝트

박주현·2023년 3월 30일
0

1. 8lette 향수 쇼핑몰

  • 엘리스AI 트랙에서 배운 내용으로 진행한 첫번째 프로젝트
  • 프로젝트 팀명 : 팔레트
  • 프로젝트 기간 : 2023.01.30 ~ 2023.02.10
  • 프로젝트 인원 : 프론트엔드 3명 + 백엔드 3명

2. 서비스 주요 기능 설명

  1. 사용자
    • 회원 기능 : 회원가입 , 마이페이지, 로그인
    • 상품 조회 : 상품목록, 상품상세, 카테고리별 조회
  2. 관리자
    • 카테고리 관리 : 카테고리 관리(추가, 수정, 삭제)
    • 상품 관리 : 상품 상세(추가,수정,삭제)

3. 주요 기능 코드

1. 로그인
: 가장 어렵게 느껴졌던 기능이었다. 백엔드와 JWT토큰을 주고 받아서 로그인여부와 회원가입이 되어있는 사용자인지 판단하면서 로그인 기능이 작동해야하는데, 지금까지 프로젝트를 백엔드와 협력해서 해본 경험이 없어서 로그인 기능에서 많은 시간이 소요되었다.
이러한 어려움을 고민하고 백엔드 팀원과 여러가지 얘기를 해보면서 이해하다보니, 금방 해결할 수 있었고
코드를 작성한 후 생기는 오류와 클린코드를 위한 수정사항은 코치님께서 도움을 주셨다.

프론트엔드 코치님과 코드리뷰를 진행하면서, 내가 어느 부분이 취약한지와 어느 부분을 중점적으로 공부해야하는지 확실하게 알았고,
코드리뷰를 진행하면서 내가 작성한 코드가 클린코드가 아니기에, 코치님과 소통하는데에 어려움이 계속해서 발생하였다. 이러한 문제점과 경험을 토대로 클린 코드를 작성해야겠다는 다짐과 목표가 생겨서 취업을 준비하는 입장에서 협업을 위해서 클린코드를 작성하여
협업시 신속하고 정확하게 수정 및 보완할 수 있는 코드를 작성해야겠다는 목표가 생겼다.

import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
// 백엔드 데이터를 axios를 통해서 전달받음
// import {customAxios} from "../config/customAxios";
import axios from "axios";
import { useSetRecoilState } from "recoil";
import { authStatusAtom } from "../recoil/atoms/authStatus.atom";
import {regex} from "../utils/regex";
export default function Login() {
  const setAuthStatus = useSetRecoilState(authStatusAtom);
  const navigate = useNavigate();

  // 이메일이나 비밀번호가 없으면 회원가입 요청하기
  const goToMain = (values) => {
    if (email.includes("@") && password.length >= 5) {
      navigate("/main");
    } else {
      alert("가입된 회원이 아닙니다. 회원가입을 먼저 해주세요.");
    }
  };

  //이메일,비밀번호 검사
  const [emailCheck, setEmailCheck] = useState("");
  const [passwordCheck, setPasswordCheck] = useState("");

  // 버튼 구현
  const [active, setActive] = useState(false);

  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const ActiveIsPassedLogin = () => {
    return email.includes("@") && password.length >= 8
      ? setActive(true)
      : setActive(false);
  };

  const handleEmail = (event) => {
    setEmail(event.target.value);
    if (regex(event.target.value)) {
      setEmailCheck(true);
    } else {
      setEmailCheck(false);
    }
  };

  const handlePassword = (event) => {
    setPassword(event.target.value);
    if (regex(event.target.value)) {
      setPasswordCheck(true);
    } else {
      setPasswordCheck(false);
    }
  };

  // await async 사용하여 백엔드와 데이터 주고받아서 로그인 처라하기
  // 더 추가할 것
  const onClickLoginButton = async (event) => {
    await axios
      .post("api/v1/auth/login", { email, password })
      .then((res) => {
        const result = res.data;
        if (!result.error) {
          const { token, isAdmin } = result.data;
          localStorage.setItem("token", token);
          setAuthStatus((prev) => ({ ...prev, isAdmin, isLogin: true }));
          navigate("/");
        } else {
          alert("로그인 실패, 다시 시도해주세요.");
        }
      })
      .catch((err) => {
        alert("(!) 네트워크 오류, 새로고침 후 다시 시도해주세요.");
        // 백엔드 유저 세션 안끊겼을 때도 동일하게 이쪽 로직 실행.
        axios.get("api/v1/auth/logout");
        console.log({ err });
      });
  };

  return (
    <>
      <section className="Login">
        <form action="" method="post" className="loginForm">
          <h1>Shopping Mall</h1>

          <div className="emailForm">
            <input
              type="text"
              id="email"
              name="email"
              placeholder="test@example.com"
              onKeyUp={ActiveIsPassedLogin}
              onChange={handleEmail}
            />
          </div>
          <div className="passwordForm">
            <input
              type="password"
              id="pw"
              name="pw"
              placeholder="password"
              onKeyUp={ActiveIsPassedLogin}
              onChange={handlePassword}
            />
          </div>
          <button
            type="button"
            onClick={onClickLoginButton}
            name=""
            className={active ? "activeLoginBtn" : "loginBtn"}
            disabled={email === "" || password === "" ? true : false}
          >
            로그인
          </button>

          <button type="button" onClick={() => navigate("/signup")}>
            회원가입
          </button>
        </form>
      </section>
    </>
  );
}

2. 상품 등록 기능
: 상품 등록은 처음에는 단순하다고 생각했는데, 어려움이 한 가지 있었다.
바로... 상품의 이미지 등록이었다. 상품별로 각각의 이미지를 등록하는 방법을 몰라서
1차적으로 고민해봤지만 해결하지 못했고, 마감시간안에 끝내야해서 일단, 랜덤이미지 URL을 사용해서 마무리하였다.

  const handleSubmit = async () => {
    // let imageUrl = "";
    let image = "https://source.unsplash.com/random/300×300";
    let detailImage = "https://source.unsplash.com/random/300×300";

    const resultProdInfo = Object.assign(prodInfo, { image, detailImage });
    console.log(resultProdInfo);
    const registResult = await postApi("api/v1/products", resultProdInfo)
      .then((res) => res)
      .catch((err) => {
        console.log({ err });
        return null;
      });

    if (registResult && !registResult.error) {
      alert("상품 등록 완료");
    }
  };

3. 배포
: VM으로 진행한 배포는 처음 해보는 작업이라 시작부터 어려움이 있었다. 백엔드는 이미 배포가 된 상태였고, 프론트엔드가 기능구현이 늦어지는 관계로 따로 배포해야하는데 프론트엔드와 백엔드 파일을 master로 커밋하고나서 배포를 진행하면 오류가 뜨는 이슈가 생겨서 백엔드 팀원이랑 많은 고민을 하다가 백엔드 코치님께서 늦은 시간에 도움을 주시고 피드백해주신 덕분에 마무리할 수 있었다.

4. 프로젝트의 회고

  1. 소통의 문제
    : 프로젝트를 시작할 때, 프론트엔드 3명 + 백엔드 3명으로 팀이 구성되었으며, 나는 팀의 팀장과 프론트엔드를 담당하였다.
    기간이 2주인 프로젝트를 절반가량 진행했을 시점에 프론트엔드 1명이 중간에 연락두절 상태가 되었으며, 엘리스측과 협의 끝에 노트북 문제로 확인되어 프로젝트를 진행할 수 없다고 판단되어 서포터 역할을 부여했다.
    이러한 문제가 발생하기 전에 내가 팀장으로서 진행사항을 매일매일 파악했어야하는데, 항상 물어보면 실력이 안되서 강의들으면서 하느라 진행속도가 느리다는 답변만 왔기에 믿었던게 가장 큰 아쉬움이었다.
    추가적으로, 프로젝트 마감 3일전에 프론트엔드 다른 인원에게 코드에 관해서 질문을 했는데 오류가 떠서 전부다 삭제했다고 하면서 몸이 아파서 입원했다는 연락을 받았을 때에는 너무나도 당황스러웠다. 백엔드는 대부분의 기능이 마무리된 상황에서 믿었던 프론트엔드 인원들이 더이상 프로젝트를 참여할 수 없었고, 그들이 담당했던 기능을 단 1도 구현되지 않았다.
    이러한 큰 문제를 먼저 운영진과 코치님 그리고 백엔드 인원들에게 공유하고나서, 나는 혼자서 고분분투해서라도 백엔드 인원들이 고생하여 구현한 기능을 최대한 만들어보자는 마음을 갖고, 3일간 정말 2~3시간씩 쪽잠을 자면서 최대한 구현하였다.
    프로젝트를 진행하다보면 분명 많은 어려움이 있을거란걸 예상했지만, 직접적으로 경험했을때는 정말 당황했고 우울함도 있었지만, 이러한 어려운 경험을 통해서 포기하지 않는 내 자신을 보았고, 다른 인원들과 소통을 하면서 팀원들에게 많은 힘을 얻었다.
    물론, 백엔드 인원들이 구현한 기능들을 대부분 보여주지 못해서 미안한 마음이 컸으며, 이해해준 팀원들에게 감사한 마음이었다.

  2. 코드 리뷰
    : 일주일에 한번 씩 코드리뷰를 진행하여, 내 코드가 효율적으로 작성되었는지와 어떤 오류가 있어서 진행하는데에 어려움이 있는지를 코치님과 상의하는 시간을 가졌다. 위에서 언급했듯이, 코치님께서 내 코드를 이해하는데에 어려움이 있으셔서 피드백 주신내용으로 클린코드를 작성해야하는 이유와 사례에 대해서 말씀해주셨는데, 말씀해주신 내용대로 클린 코드에 중요성과 나의 목표로 발전함에 따라서
    프로젝트를 진행하면서 얻은 것 중에 뜻깊은 시간이었다.

5. 마지막으로

정말 많은 일이 있었고, 다시 생각해봐도 정말 다이나믹했던 프로젝트였다.
하지만, 포기하지 않았던 내 자신과 같이 고민하고 나의 어려움을 감싸줬던 백엔드 인원들에게 먼저 감사했다고 전하고 싶고,
현재 실무에서 바쁘신 와중에도 새벽 늦은 시간에도 실시간 회의를 통해서 도움을 주신 프론트엔드 코치님과 백엔드 코치님께 감사하고 많이 배운 뜻깊은 첫번째 프로젝트였다.
앞으로 2차와 3차 프로젝트가 남았는데, 남은 프로젝트 모두! 어떠한 일이 있어도 포기하지 않는 마음을 갖고 임해야겠다.

6. Github

profile
빌드업 막 시작하는 개발자

0개의 댓글