광고 플랫폼 대시보드 프로젝트 - 종료 후 회고

Seuling·2022년 7월 21일
0

프로젝트

목록 보기
5/7
post-thumbnail

정말 시간이 어떻게 갔는지 모르겠다.

구현해야하는 기능

내가 해야하는 기능은 이 한페이지를 구현하는 것이었다.

기능 :

  • api로 데이터를 받아와서, 수정 버튼을 클릭하여 수정 할 수 있고, 광고 만들기로 생성, 삭제 기능 구현
  • 광고 관리 페이지 상단의 드랍다운으로 전체, 현재 진행중인 광고, 종료된 광고를 filtering

말그대로 CRUD를 하는것이었다. server는 json-server라는 라이브러리를 사용하고 있고, db에 수정 삭제 기능이 연동되도록 하는 것인데, 처음에는 httprequest 부분도 너무 어려워서 값을 잘 받아오지도 못하였다.

구현 방법

Read

제일 먼저 하였던 것은 화면에 데이터 받아온것을 그대로 보여주기!

레이아웃 퍼블리싱

다음으로 하였던것은 카드 형식으로 만들어주기

카드 하나하나가 AdItem이라는 컴포넌트를만들었고, 카드를 묶은것이 Adlist 라는 컴포넌트를 만들었다.
Adlist에서 map을 돌려서 AdItem이라는 카드를 생성해줬어야했는데, AdItem에서 map을 돌렸었다.

AdItem에서 Adlist로 컴포넌트를 분리해주는 작업을 해야했다. 여기서 생겼던 어려움은 getData를 Adlist에서 해주고 AdItem 에서 Props로 보내줬어야했는데, 이 props로 넘겨주는 것 또한 타입스크립트로 처음 넘겨주다보니 해맸었다.

const AdList = () => {
  const [adList, setAdList] = useRecoilState<AdListDataType[]>(adListState);
  const { getAdList } = useAdListModel();
  
  React.useEffect(() => { 
    getAdList().then((data)=>setAdList(data))
    .catch(() => console.log("data dispatch error"));
  }, []);
  
  return (
    <AdListContainer>
      {adList?.map((aditem: AdListDataType) => (
        <AdItem key={aditem.id} aditem={aditem} />
      ))}
    </AdListContainer>
  );
};

export default AdList;

타입스크립트 너무어렵다...
({aditem:AdItemProps}) 로 했다가 한참을 해맸다..

const AdItem = ({ aditem }: AdItemProps) => {
  ~~~
}

삭제 기능

그다음으로 해줬던 일은 삭제 버튼에 기능을 연결해줬다.


  const handleDeleteClick = (
    params: number,
    e: React.MouseEvent<HTMLButtonElement, MouseEvent>
  ) => {
    deleteAdList(params);
  };


<Button size="small" variant="outlined" color="warning" onClick={(e) => {
 handleDeleteClick(aditem.id, e);}}>삭제하기</Button>

aditem.id값과 e를 파라미터로 넘겨주고 , 파라미터와 일치하는 값에 id를 지워주기!

  const deleteAdList = async (id: number) => {
    const response = await adListRequest.delete(`/${id}`);
    console.log(response.data);
  };

수정 기능 (하드코딩)

다음으로 해준일은 수정하기 버튼 기능 구현 중 하드코딩으로 수정이 되는지 확인!

   const test = () => {
     putAdItemById(1, {
       id: 1,
       adType: "web",
       title: "광고 7810",
       budget: 7810,
       status: "active",
       startDate: "2020-10-19T00:00:00",
       endDate: null,
       cost: 267144117,
       convValue: 1157942685,
       roas: 433,
     });
   };
  const putAdItemById = async (id: number, data: AdListDataType) => {
    return await adListRequest.put(`/${id}`, data);
  };

수정하기 버튼에 test()라는 함수를 연결해보고, 그대로 수정이 되는지 확인하였더니 제대로 작동함!

여기서 막막함
수정하기를 어떻게 수정한 값을 입력받고, 어떻게 보내지...??
일단 수정하기 버튼을 눌렀을 때 모달처럼 띄우면 되겠다.
그러려면, input처럼 받아오면 되는데, 이 input에는 어떻게 원래 값을 먼저보여주지 ?
ui가 같을것같은데, 컴포넌트를 같이해야하나? 분리해야하나? props는 어떻게하지?
라는 고민들을 하다가, input 또한 값을 받는거니까, 생성하기 먼저 구현해봐야겠다. 생각이들어서 방향을 바꿔서 생성하기 먼저 시도하였다.

생성하기

생성하기
먼저 AdCreateItem이라는 컴포넌트를 만들어줘서 렌딩페이지에서 불러줬다.

<AdCreateItem
            createId={createId}
            onSubmit={function (form: AdListDataType): void {
              console.log(form);
            }}
          />

또한, id값을 생성할 때 마다 바꿔줘야하는데, db의 adList의 개수를 구하고 거기에 +1을 해주었었다.

  const [adList, setAdList] = useRecoilState<AdListDataType[]>(adListState);
  let createId = adList.length + 1;

여기서 버그 발생! -> 만약 중간값을 지우면 id 값이 중복될 수 있다. 따라서 create가 안됨...
정말 1차원적인 해결은 +1이 아닌 +10000 과 같은 큰 값을 준거였다.
근본적인 해결법은 아니라 생각되었지만, 급한불부터 끄고 봐야했다!

id 값을 생성하는 법에대해 공부해봐야겠다.

AdcreateItem이라는 광고를 생성하는 부분 또한 AdItem과 UI를 같이하면 될 것 같아 AdItem의 컴포넌트를 그대로 가져와 사용할 수 없을까 ?? 라는 생각을 했지만, 그 부분은 리팩토링을 진행하고 일단은 급한대로 다시 만들어 사용했다....!

먼저 form태그를 사용하여 input값들을 받아줬고, post로 서버에 보내줬다.

const AdCreateItem = ({ onSubmit, createId }: MyFormProps) => {
  const [form, setForm] = React.useState({
    id: 0,
    adType: "",
    title: "",
    budget: 0,
    status: "",
    startDate: "",
    endDate: "",
    cost: 0,
    convValue: 0,
    roas: 0,
  });
  const { postAdItemById } = useAdListModel();
  const {
    adType,
    title,
    budget,
    status,
    startDate,
    endDate,
    cost,
    convValue,
    roas,
  } = form;
  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setForm({
      ...form,
      [name]: value,
    });
  };

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    onSubmit(form);
    setForm({
      id: 0,
      adType: "",
      title: "",
      budget: 0,
      status: "",
      startDate: "",
      endDate: "",
      cost: 0,
      convValue: 0,
      roas: 0,
    }); // 초기화
    postAdItemById({
      id: createId,
      adType: adType,
      title: title,
      budget: budget,
      status: status,
      startDate: startDate,
      endDate: endDate,
      cost: cost,
      convValue: convValue,
      roas: roas,
    });
  };
  console.log(createId);
  
    return (
    <>
         <form onSubmit={handleSubmit}>
                <CardHeader
                  title={
                    <Input
                      name="title"
                      value={title}
                      onChange={onChange}
                      placeholder="광고 제목"
                      required
                    />
                  }
                  sx={{ pb: 0 }}
                />
           ~~~
           
              <Button type="submit">등록</Button>
          </form>
    </>

form 에 handleSubmit 함수 연결, 버튼 type은 submit으로!

또한 input의 변화를 감지하기위해 onChange함수 연결

 const postAdItemById = async (data: AdListDataType) => {
    await adListRequest
      .post(`http://localhost:8000/ad-list`, data)
      .then((response) => console.log(response.data))
      .catch((e) => {
        console.log(e);
      });
  };

여기서 문제가 있었다.
원래 데이터 형식이 이런식으로 되어있었다.

때문에 타입 또한 이렇게 지정을 해주었으나,

export type AdListDataType = {
  id: number;
  adType: string;
  title: string;
  budget: number;
  status: string;
  startDate: string;
  endDate: string | null;
  report: ReportType;
};

export type ReportType = {
   cost: number;
   convValue: number;
   roas: number;
 };

왜인지는 모르겠지만.... put과 post를 해주려 할 때 ReportType 이 타입을 읽어오지 못하였다..
그렇기에 데이터 구조를 바꿔버렸다...... 급한불끄기...!!

export type AdListDataType = {
  id: number;
  adType: string;
  title: string;
  budget: number;
  status: string;
  startDate: string;
  endDate: string | null;
  cost: number;
  convValue: number;
  roas: number;
};

하지만 데이터 구조를 직접 변경하는것보다는 그 구조를 가져와서 가공을 했어야했는데, 이부분에 대해서 더 공부를 해봐야겠다..

이후 어려웠던 부분은 delete 와 put을 구현해봤기에 같은 방식으로 하면 될 줄 알았고, 형식에도 없는 id 값을 계속 같이 보내서 하루종일 해결을 못했었다.....
너무 좁은 시야에 갇혀있었던것같다.

이부분을 해결하고 나서는 속도가 났지만, 시간이 너무나 촉박했다.

수정하기

이후 바로 수정하기 기능을 다시 수정해줬다.

const { putAdItemById } = useAdListModel();

  const handleModifyClick = (
    params: number,
    e: React.MouseEvent<HTMLButtonElement, MouseEvent>
  ) => {
    putAdItemById(params, {
      id: params,
      adType: adType,
      title: title,
      budget: budget,
      status: status,
      startDate: startDate,
      endDate: null,
      cost: cost,
      convValue: convValue,
      roas: roas,
    });
  };

예전엔 console에 찍어보는걸 연습을 많이 안했던것같다.
이제 값을 눈으로 다 하나씩 찍어보며 제대로오는것을 확인하고 함수를 연결하니 어느부분에서 문제가 있는지 조금은 더 빨리 해결 할 수 있는 능력이생긴것같다.

이렇게 해서 CRUD 완성!

필터링 관련 요구사항은 시간 부족으로 진행하지못하였다.....!
UI또한 신경쓰지못하였다.
기능 구현을 우선으로 하다 시간이 너무 부족하였다.. ㅠㅠ

종료 후 회고

이번 프로젝트를 진행하며 정말 많은걸 배운것같다.
특히, CRUD......!!! 기본중의기본, console 잘 찍기, 하드코딩으로 눈으로 먼저확인해보기, 안되면 잠시 쉬어가기, 급한불끄기....
프로젝트를 진행중에 좋은 코드가 맞을까? 라는 고민과, 이런식으로 급한불 끄듯 프로젝트를 진행해도되나..??라는 고민도 많았다.
하지만 돌아가는 코드가 좋은 코드다! 라는 생각으로 먼저 급한 불을 끄려했다.
리팩토링이 시급하지만, 이번 프로젝트가 끝나고선 다른 프로젝트로 바로 들어가야만 하는 상황에서
이번 회고를 통해 다음 프로젝트 시에는 조금 더 넓게 바라보는 생각을 가져야한다는 점과, 리팩토링을 중간중간 시도할 수 있으면 시도하며 진행해 보고 싶고, 이번에 배운것들을 다음 프로젝트에 비슷한 기능이 있을 때 사용해보며 다양한 시도를 해봐야겠다.
종료 후 다시 돌아보니 문제상황 뿐만아니라 해결해나가는 사고 또한 매일 기록되어있었으면 더 좋았을 것이란 생각이 남는다.
다음 프로젝트에서는 정말 조금씩이라도 매일 적어보도록 노력해야겠다.
확실한건 1주일전과는 매우 폭발적으로 성장했다는 것이 느껴진다.

더 공부 해 봐야할 점

  • post 할 때 id 생성 해 주는 방식
  • 데이터 구조를 바꾸지 않고 가공하는 방법!

프로젝트 GitHub

광고 플랫폼 대시보드 구현과제
https://github.com/Wanted-Pre-Onboarding-FE-Team5/ad-platform-dashboard

profile
프론트엔드 개발자 항상 뭘 하고있는 슬링

1개의 댓글

comment-user-thumbnail
2022년 7월 21일

무친성장력,,에 감탄하고 갑니다

답글 달기