[20220619_2차 프로젝트 회고]

YunTrollpark·2022년 6월 19일
1

Project_3(ourTrip)

목록 보기
1/1
post-thumbnail

2차 프로젝트 회고록

시작해볼까~!

1치 프로젝트가 끝난거도 믿기지 않는데 벌써 2차 프로젝트 시작이라니...!!! 아직도 모르는거 투성이에 어설프지만 최선을 다하리라는 마음가짐으로 시작했다.

1. 팀원소개

• Front-end: 손가영, 유하은, 윤경연, 최현민
• Back-end: 정병휘, 최바다

2. 사용기술 스택

• Front-end: HTML5, Styled-Component,JavaScript(ES6), React.js, react-router ,slick (library)
• Back-end: Python, Django, MySQL, Bcrypt, pyjwt, RESTful

3. 프로젝트 계획

• 1주차: 페이지 레이아웃 끝낼 수 있는 만큼 끝내기(최대한 완성을 목적)
• 2주차: 기능 구현 및 백엔드 통신

4. 필수 구현기능

1) 메인 페이지

2) 로그인 페이지

3) 로딩 페이지

4) 항공권 리스트 페이지

• fetch, useNavigate, useLocation을 활용하여 백엔드에서 데이터를 가지고 옴
• 가지고 온 데이터를 map함수를 활용하여 정렬
• querystring을 활용하여 필터 및 정렬기능 구현

5) 결제 페이지

• 해당 항공권 리스트 페이지에서 클릭한 해당 항공권의 flight_id의 정보를 가지고 결제 페이지로 이동
• useNavigate를 사용해서 페이지로 이동함
• 동의박스까지 체크하고 나면 my page로 이동

6) my page

7) 예약 상세 페이지

8) Nav

• useLocation을 사용하여 페이지 변화할 때마다 nav 스타일링이 변화 하도록 구현
• token 유/무에 따라 변화하는 nav bar 상단 바 구현

5. 내가 맡은 역할

1) 항공권 리스트 페이지

• 주요기능: 체크박스를 통한 필터 기능 및 오른쪽 상단에 정렬기능이 있음

import React, { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import styled, { css } from 'styled-components/macro';
import CheckBox from '../../components/CheckBox/CheckBox';
import FlightList from '../../components/ReservationListCard/FlightList';

const ReservationList = () => {
  const [flightList, setFlightList] = useState([]);
  const [selectAirplane, setSelectAirplane] = useState([]);
  const [selectTime, setSelectTime] = useState([]);
  const [selectSort, setSelectSort] = useState('');
  const [airlineList, setAirlineList] = useState(AIRPLANE_LIST);
  const [timeList, setTimeList] = useState(AIRPLANE_TIME);
  const navigate = useNavigate();
  const params = useParams();

  // 백엔드랑 서버 열렸을때 사용할 함수
  useEffect(() => {
    const airplaneString = selectAirplane.map(e => `&airline=${e}`).join('');
    const timeString = selectTime.map(e => `&timefilter=${e}`).join('');
    const sortString = selectSort && `&sort=${selectSort}`;
    navigate(`?${params}${airplaneString}${timeString}${sortString}`);
    fetch(
      `http://10.58.1.178:8000/flights?date=2022-06-20&origin=CJU&destination=GMP${airplaneString}${timeString}${sortString}`,
      {
        method: 'GET',
      }
    )
      .then(res => res.json())
      .then(data => {
        setFlightList(data.results);
      });
  }, [selectAirplane, selectTime, selectSort]);

  const handleSelectAirplane = airplanes => {
    if (selectAirplane.includes(airplanes)) {
      setSelectAirplane([
        ...selectAirplane.filter(airplane => airplane !== airplanes),
      ]);
      airlineChecked(airplanes);
    } else {
      setSelectAirplane(prev => [...prev, airplanes]);
    }
  };

  const handleSelectTime = times => {
    if (selectTime.includes(times)) {
      setSelectTime([...selectTime.filter(time => time !== times)]);
      timeChecked(times);
    } else {
      setSelectTime(prev => [...prev, times]);
    }
  };

  const handleSelectSort = e => {
    const { value } = e.target;
    if (selectSort.includes(value)) {
      setSelectSort([...selectSort.filter(id => id !== value)]);
      return;
    } else {
      setSelectSort(value);
    }
  };

  const airlineChecked = id => {
    const checkedItems = airlineList.map(item => {
      if (item.id === id) return { ...item, isChecked: item.isChecked };
      else return item;
    });
    setAirlineList(checkedItems);
  };

  const timeChecked = id => {
    const checkedItems = timeList.map(item => {
      if (item.id === id) return { ...item, isChecked: item.isChecked };
      else return item;
    });
    setTimeList(checkedItems);
  };

  const totalSum = flightList.length;

  return (
    <div>
      <Body>
        <NavLayout>여기는 Nav</NavLayout>
        <ReservationListWrap>
          <CheckBox
            handleSelectTime={handleSelectTime}
            handleSelectAirplane={handleSelectAirplane}
            AIRPLANE_LIST={AIRPLANE_LIST}
            AIRPLANE_TIME={AIRPLANE_TIME}
          />
          <ReservationListContainer>
            <SearchFilter>
              <SearchInfo>
                <TextSpan>
                  <span>검색결과 총 {totalSum}</span>
                </TextSpan>
                <InfoTextSpan>
                  성인 1인 기준 편도 요금입니다. (세금 및 수수료 포함)
                </InfoTextSpan>
              </SearchInfo>
              <Filter onChange={handleSelectSort}>
                {SORT_OPTION.map(({ id, label, value }) => (
                  <option key={id} value={value}>
                    {label}
                  </option>
                ))}
              </Filter>
            </SearchFilter>
            <FlightInfo>
              <DepartBox>가는편</DepartBox>
              <LocationInfo>김포</LocationInfo>
              <ImgData src="/images/smallArrow.svg" alt="arrow" />
              <LocationInfo>제주</LocationInfo>
              <FlightDate>06월20일()</FlightDate>
            </FlightInfo>

            <CardList>
              {flightList && <FlightList flightList={flightList} />}
            </CardList>
          </ReservationListContainer>
        </ReservationListWrap>
      </Body>
    </div>
  );
};
export default ReservationList;
체크박스는 별도의 컴포넌트로 빼서 활용을 했습니다.

2) 주요 코드

주요 함수:
• incldues
• filter(https://velog.io/@cadyky95/filter-map-구조분해-할당)
• spread operator(https://velog.io/@cadyky95/20220619스프레드-연산자Spread-Operator)

  const handleSelectAirplane = airplanes => {
    if (selectAirplane.includes(airplanes)) { // 만약에 selectAirplane에 airplanes가 있다면
      setSelectAirplane([ // setSelectAirplane에 selectAirplane을 복사해서
        ...selectAirplane.filter(airplane => airplane !== airplanes),
        //filter를 하는데 airplane에 airplane에서 airplanes가 같지 않다면
      ]);
      airlineChecked(airplanes); //airlineChecked에 airplanes를 업데이트 해라
    } else { // 그게 아니라면 setSelectAirplane에 ...prev를 복사하고 거기에 airplanes를 추가해라
      setSelectAirplane(prev => [...prev, airplanes]);
    }
  };
const airplaneString = selectAirplane.map(e => `&airline=${e}`).join('');
// selectAirplane에 map을 사용할건데 e라는 매개변수를 {e}넣어줄거고, ''빈문자열로 합쳐줌

주요 함수:
• map(https://velog.io/@cadyky95/filter-map-구조분해-할당)

import React, { useState } from 'react';
import styled, { css } from 'styled-components/macro';
import CheckedList from './CheckedList';
import { IoIosArrowUp, IoIosArrowDown } from 'react-icons/io';

const CheckBox = ({ // 부모에서 사용한 함수인데 props로 내려줌
  handleSelectAirplane,
  handleSelectTime,
  AIRPLANE_LIST,
  AIRPLANE_TIME,
}) => {
  const [clickedTab, setClickedTab] = useState(true);

  return (
    <div>
      <CheckBoxContainer>
        <ButtonAlign>
          <SortAirplane>항공사</SortAirplane>
          <TabButton onClick={() => setClickedTab(!clickedTab)}>
            {clickedTab ? <IoIosArrowUp /> : <IoIosArrowDown />}
          </TabButton>
        </ButtonAlign>
        <AirplaneList>
          {clickedTab &&
            AIRPLANE_LIST.map(({ id, airline, isChecked }) => ( // id, airline, isChecked를 구조분해 할당해줌
              <ListAlign key={id}>
                <Label>
                  <CheckInput
                    type="checkbox"
                    key={id}
                    airline={airline}
                    onClick={() => handleSelectAirplane(id)} //onClick 이벤트가 발생할때 id를 인자로 받음
                    defaultChecked={isChecked}
                  />
                  {airline}
                </Label>
              </ListAlign>
            ))}
        </AirplaneList>
        <SelectUl>
          <CheckedList
            handleSelectTime={handleSelectTime}
            AIRPLANE_TIME={AIRPLANE_TIME}
          />
        </SelectUl>
      </CheckBoxContainer>
    </div>
  );
};
export default CheckBox;

아쉬운점

useParams를 사용하면 useState없이 구현이 가능하다고 했는데, 3일을 꼴딱 찾다가 못찾아서 포기하고 동기분의 도움을 받아 querystring을 만들 수 있었다. 그래서 추후에 좀 더 공부를 하고 다시 리팩토링할때 useParams를 활용하여 수정하고 싶다. 내가 아직 손이 느려서 백엔드가 만든 API 일부를 사용하지 못한게 너무 아쉬웠다. 그리고 중간에 rebase를 하다가 코드를 날려서 밤을 샜는데, 이 경험 덕분에 멘토님에게 rebase에 대해 제대로 배웠다. 다음에는 절때 절때 같은 실수를 하지 않을 것이다!!! 이렇게 구르고 넘어지고 깨지면서 단단해지는 나의 멘탈...!!!

잘한점👍

이번에는 백엔드와 노션으로 맞춰야 하는 key값이나 데이터의 구조, 형태를 실시간으로 업데이트 해서 나중에 통신할때 오류나 충돌없이 빠르게 끝낼 수 있었다.

그리고 Trello를 활용하여 같은 팀원들의 진행 상황이나, 나의 현재 진행 상황을 공유해서 팀원들의 작업 상황을 한번에 파악 할 수 있었다.

그리고 문제 상황이 생기면 서로 좋게좋게 말로 항상 풀었고, 하루에 한번 미팅을 통해서 서로 힘든 부분이나 고충을 이야하는게 정말 많은 도움이 됐다. 내가 에러가 발생해도, 다른 팀원이 에러가 발생해도, 다같이 붙어서 무엇이 문제인지 해결하는 과정이 가장 인상에 남는다. 나중에 취직을 하면 이런 일련의 경험이 프로젝트를 할 때 힘이 되어줄것이라 생각한다.

프로젝트를 마치며!🤟

내가 항상 핸드폰 배경화면에 저장해두고 보는 문장이 있다.

"Denk nicht, die Welt hat dich verworfen. Die Welt hat dich nie besessen."
"세상이 너를 버렸다고 생각하지 말라. 세상은 너를 가진적이 없다."

이번에 git rebase를 진행하다가 코드가 복구가 안되고 날아갔을때 정말 멘탈이 많이 무너졌는데, 내가 맡은 부분을 다 하지 못하면 팀원분들께 피해가 가서 책임감을 가지고 완성시켰다. 내가 나를 포기만 안하면 어떻게든 된다는 것을 깨닫게 된 프로젝트였다!
이런 내가 내일 기업협업을 나간다는게 떨리고, 무섭고, 두렵기도 하지만 프로젝트 시작전에도 이렇게 걱정을 많이 했지만 결국 전부 해내지 않았는가!!! 앞으로도 이런 경험들을 발판 삼아 더욱더 성장한 내가 되기를 바란다!!! 파이팅!!!

https://youtu.be/B9LIYb3BIQ8
유튜브에서 본 인상적인 영상! 나는 제발 걱정은 좀 접어두고 앉아서 뭐라도 해야 한다고 느꼈던 영상...

profile
코딩으로 세상에 이야기하는 개발자

0개의 댓글