[원티드 프리온보딩 프론트엔드 과정] 3차 과제, 견적 요청 페이지

♦️ 3차 과제 : 견적 요청 페이지

프로젝트 소개

파트너스 견적 요청 페이지를 구현하는 것을 목표로 하는 프로젝트입니다.

링크

github repo
배포 링크

구현사항

☑️ json-server&dev-server 세팅(concurrently)하여 가상의 데이터 서버 구성

☑️ json-server로 mock rest-api server 연동

☑️ mock rest-api로 data 호출 및 type 지정

☑️ theme, global style 지정

☑️ 대시보드 메인보드 UI 스타일링

☑️ 대시보드 카드 UI 스타일링

☑️ 대시보드 Modal UI 및 기능 구현

☑️ 대시보드 메인 반응형 UI 스타일링

☑️ heroku를 이용한 json-server 배포

기능별 영상

기능 전체

모바일



[원티드 프리온보딩 코스]의 이번 과제는 Typescript를 사용하여 figma에 작성된 가이드 그대로 구현하고, json-server 로 mock rest-api server를 띄워서 작업하라는 조건이 있었다. json-server를 사용해서 프로젝트를 진행하는 것도 처음이었고, 또 아직 익숙하지 않은 TypeScript 라는 언어를 사용해서 구현해야 했기 때문에 이전의 과제보다 꽤나 긴장한 상태에서 프로젝트를 진행했던 것 같다.

다만 팀원들과 회의 중에 figma의 구현내용을 함께 살펴보니 생각보다 기능 구현에 대한 볼륨이 크지 않다고 느꼈다. 구현해야 할 주요 기능들이 많지 않아서 어떻게 테스크를 나눠야할지 난감했지만 과제의 구현 요건이 json server를 띄우고, 필터링을 해주는 것이었기 때문에 일단 이렇게 크게 두가지의 요건으로 나눠서 2명이 짝을 이뤄 테스크를 가져가기로 했다. 사다리 타기(ㅎㅎ)를 통해서 필터링 로직은 다른 팀원 둘이 맡게 되었고, json server 와 세팅, UI 컴포넌트 및 모달 구현과 최종 배포를 나와 다른 팀원이 맡아서 진행했다.

새로 배웠거나 고민했던 지점

🔹 Typescript 사용하기

프로젝트 시작 전에 틈틈이 공부를 해오긴 했지만 타입스크립트를 프로젝트에 직접 적용해서 사용해본 건 처음이었기 때문에 불안한 상태였다. (걱정이 좀 많은 타입..) 게다가 타입스크립트에 익숙하지 않았던 팀원들이 대부분이었기에 초반에 세팅을 할 때나 간단한 theme 스타일을 적용하는 것에도 조심스러웠던 것 같다.

theme 설정하기

import { DefaultTheme } from "styled-components";

const theme: DefaultTheme = {

  color: {
    WHITE: "#ffffff",
    BLACK: "#000000",
    BLUE: "#1565C0",
    SKY: "#2196F3",
    GRAY: "#E5E5E5",
    LIGHTGRAY: "#F5F5F5",
    DARKGRAY: "#C2C2C2",
    LIGHTBLUE: "#2196F3",
    LIGHTSKY: "#BBDEFB",
    ORANGE: "#FFA000",
    FONTCOLOR: "#323D45",
    FONTGRAY: "#939FA5",
  },

  size: {
    MOBILE: 360,
  },
};

export { theme };

figma 스타일 가이드 그대로 구현해야 했기 때문에, 먼저 기본적인 theme을 초기 세팅에서 공유하고 다른 팀원들이 컴포넌트를 생성할 때 사용할 수 있도록 하는 게 좋을 것 같았다. figma에서 지정한 color와 mobile 사이즈는 정해져있었기 때문에 먼저 color와 mobile의 값부터 지정해주었다.

theme의 type 지정하기

import "styled-components";

declare module "styled-components" {
  export interface DefaultTheme {
    // basicWidth: string;

    color: { [key in Color]: string };
    size: { MOBILE: number };
  }
}

color의 key(COLOR_이름)에 지정된 value 값들은 모두 string 타입이었기 때문에 color: { [key in Color]: string }로 타입을 지정해주었고, size의 MOBILE은 number 타입이었기 때문에 { MOBILE: number }로 지정해주었다.

import { theme } from "./styles/theme";
...

const PaddingWarp = styled.div`
  // 이런 식으로 theme을 props 받아서 사용하면 됩니다.
  background-color: ${({ theme }) => theme.color.red};
  @media screen and (max-width: ${({ theme }) => theme.size.MOBILE}px) {
  }
`;

초기세팅 이후 팀원들이 theme을 가져와 사용할 때, 헷갈리거나 이해하는데 낭비하는 시간이 없도록 사용 예시도 함께 공유했다. 초기 세팅 중에 팀원들과 Typescript를 실시간으로 공부하면서 적용했기 때문에 내심 든든했던 것 같다. 지금 돌아보면 웃음이 날 정도로.. 아주 간단한 type 지정이었지만 그간 공부한 대로 프로젝트에 type을 지정하고 사용하는 것은 처음이었기 때문에 특히나 기억에 남는 것 같다.

🔹 mock rest-api server를 활용한 데이터 관리

json-server로 mock rest-api server 세팅하여 가상의 데이터 서버를 구성해야 된다는 조건 사항을 따르기 위해서는 json-server(https://www.npmjs.com/package/json-server)를 이용하여 백엔드 서버 없이 mock rest-api server 로 프로젝트를 구현해야 했다. 사다리 타기로 이번 과제에서 팀장을 맡게 되었던 터라 내가 초기 세팅을 맡아 진행하게 되었는데, 다른 팀원들이 원활하게 컴포넌트를 만들고 작업하기 위해서는 기본적인 라이브러리를 설치하는 것 외에도 json-server를 띄우고 작동시켜서 mock data를 받아오는 과정까지는 미리 세팅을 해줘야 할 것 같았다. json-server 설치에 대한 부분은 온라인 사수(;;) 분들의 도움을 많이 받았다. (* 레퍼런스 참조) 먼저, json-server를 이용하기 위해서 json-server를 설치하는 과정이 필요하다. json-server는 가상의 데이터 서버를 구성할 수 있도록 도와주는 라이브러리이다. (후에 다시 거론하겠지만, 이때 나는 당연히 json-server을 설치했다고 생각했는데 설치가 되지 않았고 이로 인해 기나긴 삽질을 하게 된다..)

json-server 설치하기

yarn glodbal add json-server

터미널에서 json-server를 설치하면, 이제 서버에서 띄울 Mock 데이터를 생성해주어야 한다. 나는 utils 폴더 안에 api 폴더를 생성하여 그 안에 data.json이라는 파일을 만들고, 우리가 사용할 가상의 데이터를 입력해주었다.

가상의 데이터(data.json) 생성하기

{
    "requests": [
      {
        "id": 1,
        "title": "자동차 시제품 제작",
        "client": "A 고객사",
        "due": "2020.12.14",
        "count": 2,
        "amount": 100,
        "method": ["밀링", "선반"],
        "material": ["알루미늄"],
        "status": "대기중"
      },
      ...
  }

그리고 이 mock 데이터의 타입을 지정해주는 작업을 추가적으로 진행했다.

가상의 데이터(data.json)에 데이터 타입 지정하기

utils/api/data.types.tsx

import React from 'react';

export interface IRequests {
  id: number;
  title: string;
  client: string;
  due: string;
  count: number;
  amount: number;
  method: string[];
  material: string[];
  status: string;
}

export interface RequestsArray extends Array<IRequests> {}

export type IGetData = React.Dispatch<
  React.SetStateAction<RequestsArray | null>
>;

mock data가 담긴 data.json를 담은 폴더에서 data.types.tsx 를 생성하고, package.json에서 json-server 를 구동할 수 있도록, scripts를 수정해주었다.

json-server 명령어 추가

 "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "mockserver": "json-server --watch --delay 500 --port 4000 src/utils/api/data.json",
 },

craco 는 CRA + TypeScript에서 절대경로를 설정할 때 사용하는 모듈이다. craco 설치 방법은 여기서 (* 레퍼런스 참조) 했다.

이제 json-server 에서 데이터를 받아올 수 있게 되었다. 하지만 여기서 문제가 있었다. 리액트 개발 서버와 json-server를 각각 열어서 함께 구동해야만 했기 때문이다. 이 두 로컬 서버를 매번 열어야 한다는 불편함을 어떻게 해결할 수 없을까 고민하다가 검색을 해보니 리액트 개발 서버와 json-server를 동시에 실행시켜주는 concurrently 라이브러리가 존재한다는 걸 알게 되었다. (유레카!) 나는 바로 concurrently 라이브러리를 추가로 설치해주었다.

concurrently 설치하기

CRA는 기본적으로 개발 서버가 주어지기 때문에 json-server 또는 node.js로 구축한 서버를 동시에 실행시키려면 각각의 명령 프롬프트를 사용해야 하는데 concurrently 라이브러리를 사용하면 이를 한 번에 실행시킬 수 있게 된다. (* 레퍼런스 참조)

yarn add concurrently

yarn(혹은 npm)으로 concurrently 설치를 마치고 나면, package.json에 concurrently를 사용할 수 있도록 scripts 명령어를 추가해준다.

concurrently 명령어 추가

  "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "mockserver": "json-server --watch --delay 500 --port 4000 src/utils/api/data.json",
    "dev": "concurrently \"yarn start\" \"yarn mockserver\"",
    "eject": "react-scripts eject"
  }

이제 yarn dev 하나만 입력해도 (리액트 개발 서버와 json-server를 각각 구동하지 않고) json-server에서 가상의 데이터를 받아올 수 있게 되었다.

json-server 열기

yarn dev

json-server로 가상의 데이터 서버를 세팅하는 것까지 모두 완료했다. 이제 이 서버로부터 data.json을 받아와야 했다. 데이터를 사용할 컴포넌트로 가상의 데이터(data.json)를 받아올 생각이다.

가상의 데이터(data.json)를 받아오기

// type
import { RequestsArray } from "@/utils/api/data-types";

const MainBoard = () => {
  const [data, setData] = useState<RequestsArray | null>();

  const getData = async () => {
    const json = await (
      await fetch("http://localhost:4000/requests")
    ).json();
    setData(json);
  };
  
  useEffect(() => {
    getData();
  }, []);
    
  return (
  ...
  	{data?.map((data, idx) => (
    	<React.Fragment key={idx}>
      	<Card items={data} />
    	</React.Fragment>
  	))}
  ...
  );

yarn dev로 띄운 localhost:4000/requests api를 fetch로 가져와 data 상태에 넣어주는 함수를 작성한 뒤, useEffect() 로 해당 함수를 실행해서 컴포넌트가 렌더링되자마자 데이터를 받아올 수 있도록 했다. 앞서 많은 과정들을 거치며 제대로 데이터를 받아올 수 있을지 걱정하고 있었는데 다행히 정상적으로 데이터가 받아와지는 것까지 확인하니 안심이 됐다. 물론 다른 팀원들이 컴포넌트를 생성하면서 바로 data를 토대로 구현할 수 있도록 map으로 props 을 해주었다.

🔹 Heroku로 Json-server를 함께 배포하기

그동안 json-server를 통해 데이터 서버를 직접 구현하지 않아도 실시간으로 API를 받아와 편리하게 테스트할 수 있었다. 하지만 배포 후에도 해당 API를 이용하기 위해서는 json-server도 함께 Heroku로 배포를 해줘야하는 문제가 있었다. 다른 팀원들은 각자 맡은 테스크가 아직 끝나지 않은 상태였고, 여유가 있는 사람은 나뿐이었기에 내가 배포를 맡아 진행하기로 했다. 먼저 Heroku로 json-server를 배포하는 방법을 검색(* 레퍼런스 참조)을 통해 알아냈고, 이를 참조해서 배포를 진행하기로 했다.

Heroku 를 이용하기 위해서는 당연히! Heroku에 가입하는 과정이 필요하다. 나는 이분의 벨로그(* 레퍼런스 참조)를 참조해서 Heroku에 가입하고 배포할 프로젝트 앱을 생성했다.

Heroku 가입/준비 순서

Heroku 사이트로 이동 Heroku/login → Create a new app으로 배포를 하게 될 새로운 앱 생성 → App name 및 region을 지정 → Heroku CLI를 설치해줘야 한다.(사용 중인 OS에 맞게 다운로드 해서 설치) → Heroku CLI 설치 후 터미널에서 heroku —version 명령어를 통해 정상적으로 설치되었는지 확인 → 터미널에서 heroku login 명령어를 통해 Heroku 로그인을 진행. → 터미널에서 배포 할 프로젝트 위치로 이동

git 레파지토리 원격 연결

$ cd my-project/
$ git init
$ heroku git:remote -a <app-name>

→ 마지막으로 배포 할 프로젝트 위치에서 git 레파지토리를 연결하면 Heroku를 사용하기 위한 준비는 끝이다.

Heroku에 가입하고 배포하기 위한 준비 과정은 많은 온라인 사수님(ㅎㅎ)들이 훨씬 더 자세하게 알려주고 계시므로, 간단하게 내가 진행한 단계만 순서대로 적었다. 사실 여기까지는 크게 어렵지 않았는데, 문제는 Heroku로 json-server를 함께 배포해야 되는 단계가 남아있었다. 역시 레퍼런스(* 레퍼런스 참조)를 참조해서 남은 단계도 진행할 수 있었다.

json-server를 배포해서 데이터의 api를 받아오려면, 데이터가 작성된 파일이 필요했다. 먼저, 프로젝트 최상위 디렉토리(root)에서 data.json 파일을 만들고 이전에 가상의 데이터로 사용했던 utils/api/data.json을 그대로 긁어와서 붙여넣기를 해줬다.

data.json

{
    "requests": [
      {
        "id": 1,
        "title": "자동차 시제품 제작",
        "client": "A 고객사",
        "due": "2020.12.14",
        "count": 2,
        "amount": 100,
        "method": ["밀링", "선반"],
        "material": ["알루미늄"],
        "status": "대기중"
      },
      ...
  }

그리고 프로젝트 최상위 디렉토리(root)에서 우리가 사용하는 data를 담아놓은 data.json 과 스태틱 파일을 호스팅하기 위한 server.js 파일을 만들어주었다.

server.js

const jsonServer = require("json-server");
const server = jsonServer.create();
const router = jsonServer.router("./data.json");
const middlewares = jsonServer.defaults({
  static: "./build",
});
const port = process.env.PORT || 4000;

server.use(middlewares);
server.use(
  jsonServer.rewriter({
    "/api/*": "/$1",
  })
);

server.use(router);

server.listen(port, () => {
  console.log("server is running");
});

이제 package.json 에서 scripts를 수정한다. 그동안 localhost를 실행시켜줬던 "craco start"의 명령어인 "start"를 "start:dev"라는 명령어로 바꿔주고, 기존의 "start" 명령어에는 node가 server.js를 실행할 수 있도록 "node server.js"로 수정해줬다.

package.json

  "scripts": {
    "start": "node server.js",
    "start:dev": "craco start",
    "build": "craco build",
    "test": "craco test",
    "mockserver": "json-server --watch --delay 500 --port 4000 src/utils/api/mockdata.json",
    "dev": "concurrently \"yarn start:dev\" \"yarn mockserver\"",
    "eject": "react-scripts eject"
  },

앞서 모든 작업이 완료되면 드디어 배포만 남은 것이다! 레퍼런스 를 참조해서 git 사용법과 동일하게 프로젝트를 add → commit → push 해주었다. (물론 heroku에 로그인을 하고, heroku와 배포할 프로젝트가 원격으로 연결되어 있는 상태여야 한다.)

$ git add .
$ git commit -am "first commit"
$ git push heroku master -> 이 명령어에서 에러가 발생한다면 git push heroku HEAD:master로 하길

그런데, git push heroku master로 배포를 했더니 계속 에러가 발생했다. 검색에 (* 레퍼런스 참조) 에 따르면 git push heroku master로 명령어를 실행했을 때 에러가 발생하면, git push heroku HEAD:master로 다시 배포 명령어를 실행해주라고 나와있었다. 그리고 이 방법으로 실행해주었더니 에러없이 배포가 완료되었다. Heroku로 배포가 완료되면, URL 주소를 확인하고 이 주소로 API를 fetch 해올 수 있도록 코드를 수정해준다.

변경 전

  const getData = async () => {
    const json = await (
      await fetch("http://localhost:4000/requests")
    ).json();
    setData(json);
  };

변경 후

  const getData = async () => {
    const json = await (
      await fetch("https://ateamventures.herokuapp.com/requests ")
    ).json();
    setData(json);
  };

주소 수정이 완료되면, Heroku로 배포하던 때와 동일하게 add → commit → push(git push heroku HEAD:master) 해주면 배포의 마지막 단계가 끝이 난다. 이후 코드를 수정하고 재배포를 할 때도 같은 방식으로 진행하면 된다.

$ git add .
$ git commit -am "first commit"
$ git push heroku master -> 이 명령어에서 에러가 발생한다면 git push heroku HEAD:master로 하길

배포 페이지가 왜 빈 페이지로 나오는데? 😂

Heroku에 배포하기 위한 모든 단계를 완료한 뒤 에러 없이 push까지 진행했는데, 막상 배포한 주소로 이동해보면 페이지가 (중간에 아무런 에러가 발생하지 않았음에도) 빈 화면으로 뜨는 문제가 발생했다. 과제 제출까지 시간이 얼마 남지 않은 상태라서 매우 멘붕.. 이 왔지만 다시 차근차근 배포 튜토리얼을 확인하며 배포를 위해 생성했던 파일들과package.json 을 살펴봤다. 파일을 다시 지우고, 폴더를 생성해서 이동도 하면서 온갖 삽질을 하였는데, 어이없게도 해당 package.jsonjson-server가 설치가 안되어 있는 것을 발견했다. 😇 앞서 분명히 yarn glodbal add json-server 명령어로 json-server를 설치하고 concurrently 라이브러리까지 추가로 설치한 뒤, 서버 API를 통해 가상의 데이터까지 받아왔다고 생각했는데 알고보니 해당 package.jsonjson-server가 설치가 안되어있던 것이었다. 덕분에 꽤나 오랜 시간 삽질을 했는데.. 다시 생각해봐도 정말 황당한 실수였다. 게다가 json-server 를 설치하지도 않았는데, 가상의 데이터를 받아오고 있었으니 중간에 문제를 인지하지 못했던 것이다.

(고통 받았던 삽질의 시간.. 눈물이 난다.. )

문제를 인지한 후 바로 json server를 설치하고 다시 push를 했더니.. 다행스럽게도 제출 바로 직전에! 배포가 성공적으로 완료되었다. 생각지도 못한 이슈로 삽질을 하게 되면서 점점 과제 제출 시간에 가까워졌고 그러면서 혹시나 팀원들에게 민폐를 끼칠까봐 혼자 어찌나 진땀이 나던지.. 하지만 끝까지 포기하지 않고 차근차근 시도했더니 결국 배포에 성공할 수 있었다. 하핫.

🔹 팀 노션으로 효율적인 팀 협업 진행하기

세번째 과제를 진행하면서, 이전에 내가 만들었던 팀 노션 페이지가 생각보다 활용도가 높지 않은 것 같다고 느껴졌다. 팀원들과 더 효율적으로 소통하고 팀원들 간에 보다 쉽게 정보를 공유하기 위해서 두번째 프로젝트가 끝난 후 시간적인 여유가 있을 때마다 노션 페이지를 틈틈이 수정했다. 결과적으로는 팀원들의 반응도 좋았고, 팀에 조금이나마 긍정적인 영향을 줄 수 있어서 뿌듯한 일이었다.

팀 노션 메인 페이지

팀에서 회의 혹은 스크럼을 할 때마다 우리가 나눈 모든 논의들을 기록하고 후에도 복기할 수 있도록 정리하고자 했다. 다른 팀원들도 이 기록물들을 용이하게 사용할 수 있도록 아예 템플릿을 만들었는데 이것도 반응이 매우 좋았다!

회의록

회의록스크럼

코딩 컨벤션 및 깃 커밋 가이드 라인

이전에 우리가 구두로 합의하고 두서없이 정리되어있던 코딩 컨벤션이나 커밋 가이드 라인을 다시 정리했고, 다른 팀원들의 의견도 종합해서 최종적으로 수정한 내용을 공유해서 이번 프로젝트에 적용할 수 있었다.


코딩 컨벤션깃 커밋 가이드 라인

프리온보딩 수업에서 멘토님께서 팀 협업이 얼마나 중요한지에 대해 이야기하신 적이 있다. 이 부분을 설명하시며 다른 팀분들이 어떻게 노션을 통해서 효율적으로 팀 협업을 진행하고 있는지에 대해 예시로 몇가지를 보여주셨었는데 팀 노션 페이지를 수정할 때 참고가 많이 됐다.

🔹 리팩토링 진행하기 (업데이트 예정)

✍🏻 회고

이번 프로젝트에서 필터링 로직은 다른 팀원 둘이 맡게 되었고, json server 와 세팅, UI 컴포넌트 및 모달 구현과 최종 배포를 나와 다른 팀원이 맡아서 진행했었다. 프로젝트의 주요 구현 기능이 4명으로 나누기엔 애매한 부분이 있어서 주요 요건을 토대로 나눈 것인데, 애초에 UI 컴포넌트 각자 나눠서 진행하고 필터링 로직을 페어 프로그래밍을 통해 팀원 모두가 로직을 함께 짜보면 어땠을까 하는 작은 아쉬움이 있다. (필터링 로직을 직접 구현하고 싶었기 때문에 이 부분은 개인적으로 리팩토링으로 진행해볼까 한다.)

세번째 과제를 진행하면서, 체력적으로 조금 피곤한 상태였지만 팀장으로서 다른 팀원들에게 누가 되지 않고, 과제 뿐만 아니라 다른 부분에서도 도움이 될 수 있도록 다방면에서 노력했던 시간이었다. 팀의 협업을 목표로 노션을 활용해서 팀원들과 정보를 공유하려고 했고, 코딩 컨벤션과 깃 커밋 가이드를 함께 지정해서 사용했다. 세번째 과제이니만큼, 팀원들과 손발이 맞는 느낌이 들었고 소통이나 커뮤니케이션에서도 크게 어려움이 없었던 것 같다. 그리고, 초기 세팅부터 테스트 서버를 열고 배포까지 해본 경험은 처음이었기 때문에(물론, Typescript를 적용한 것도!) 개인적으로도 많은 성장을 한 프로젝트라고 생각한다.

🗂 Reference


CRA+Typescript 절대경로 설정(w/craco)
Json-server & Concurrently
Heroku로 간단하게 웹 사이트 배포하기
Heroku로 json-server를 함께 배포하기

좋은 웹페이지 즐겨찾기