Skip to content

matty255/Schedule_EngAll

Repository files navigation

Schedule_EngAll

원티드 프리온보딩 기업과제 Week-4-2 Schedule

제작 기간 : 2022 - 07 - 27 ~ 2022 - 07 - 29

실행방법

- mac일 경우
1. git clone https://github.com/Wanted-Pre-Onboarding-Frontend-2/Wan2trip.git
2. cd [folder name]
3. yarn install
4. yarn start
하면 json-server가 같이 실행됩니다.

- window일 경우
1. git clone https://github.com/Wanted-Pre-Onboarding-Frontend-2/Wan2trip.git
2. cd [folder name]
3. yarn install

4. 터미널을 2개로 분할
5. 1번터미널 : yarn start
6. 2번터미널 : cd [folder name]
7. 2번터미널 : yarn server

json-server를 따로 켜주셔야 합니다.

사용 스택

  • typeScript : 타입스크립트로 build했습니다.

  • eslint / prettier : 깔끔하고 일관된 코드스타일을 위해 사용하였습니다.

  • recoil : 클라이언트 측 전역 데이터를, 보일러 플레이트 없는 수준으로 구현 가능했기에 주어진 시간 대비 최고의 효율이라고 생각되어 사용하였습니다.

  • json-server & axios : 모듈화된 get, post api를 제작하고 서버데이터를 구축하기 위해 사용하였습니다.

  • tailwindCss & tailwind-styled-components : 번들 크기를 줄이고 최소한의 코드와 시간으로 요구 레이아웃(반응형)을 구현하기 위해 사용하였습니다.

  • date-fns : 날짜/시간 조작을 이용하여 시작시간만을 받아와 다른 사용해야 할 데이터들을 제작하기 위해 사용하였습니다.

  • react-router-dom : 딜레이 없는 빠른 라우팅과 리다이렉트 지원을 위해 사용하였습니다.

기능 구현

주간 테이블

  • 날짜는 표시되지 않습니다.✅

    • 날짜가 표시되지 않는 주간 시간표를 제작하였습니다.
  • 주간 일정 데이터를 가져와 요일 시간 별로 노출합니다.✅

    • Date 객체를 사용하고자 했으나 이번 과제의 특성(날짜는 체크하지 않음)상 다음날 만드는 데이터가 무조건 늦게 정렬되었습니다.
    • 차선으로 am/pm 여부와 시간단위 숫자에 이중정렬을 걸었습니다.
  • 각 일정은 x버튼을 누르면 삭제 되어야 합니다.✅

    • hook으로 컨펌 로직을 분리하고 삭제시 컨펌메세지를 띄워주었습니다.
  • add class schedule 버튼을 누르면 수업 일정추가 페이지로 이동합니다.✅

    • add페이지와 view페이지를 만들고 첫 진입시와 존재하지 않는 주소일때 리다이렉트될 home페이지를 만들었습니다.
  • 반응형 웹 + 테이블 ✅

    • 각 카드크기를 고정하고 가로화면에 overflow를 적용해 디스플레이가 깨지지 않게 했습니다.

수업 일정 추가

  • 수업 일정 추가 버튼을 누르면 수업 일정 추가가 열립니다.✅

  • 저장 버튼을 누르면 수업 일정 보기로 돌아갑니다.(주간 테이블)✅

  • 수업 일정 추가 페이지에서 시작시간을 선택할 수 있습니다.✅

    • 시작시간은 5분 간격으로 제한됩니다.✅

      • 필요한 시간단위를 계산하는 수식을 만들어 작업량과 코드양을 조금 줄였습니다.
    • 시작 시간의 범위는 0~23시까지 입니다.✅

      • 마지막 시작시간의 경우 23시에 마쳐야 하므로 dropdown에서 am -> pm으로 변경시 시간이 22시 20분 이상이라면 초기화되도록 했습니다.
    • 수업 시간은 항상 40분입니다.✅

      • 로직을 hook으로 분리 : 시작시간을 받아와서 date-fns로 시작시간, 끝시간, json에 들어갈 Date객체, timeFilter 배열을 리턴하도록 했습니다.

  • 수업 일정을 추가할 때 똑같은 시간에 여러 요일을 선택할 수 있습니다.✅

    • 모든 요일 선택기능을 추가하였습니다.
    • 여러 요일을 선택해서 각 주소로 제출할 수 있도록 하였습니다.
  • 새로 추가된 일정이 주간 테이블에 노출됩니다.✅

    • 주간 페이지 진입시 useEffect 사용으로 api를 받아오도록 했습니다.
  • 페이지가 다시 로드 되어도 수업 일정이 유지 되어야 합니다.✅

    • json-server를 사용하여 캐싱 이슈와 데이터 유지 문제를 해결하였습니다.
  • 반응형 웹 + 작성 폼 ✅

    • 작성 폼의 버튼들에 각각 플렉스를 적용하여 스크린의 크기에 따라 새로이 배치되도록 하였습니다.
  • 중복된 날짜 제출 금지 ✅

    • 중복된 날짜가 있을 경우 날짜가 중복된다고 알려주고 모든 요일 인풋을 해제하며 버튼이 disable처리 됩니다.
  • 최대한 사용자에게 다양한(필요한) 메시지를 주기 ✅

    • 요일이나 시간을 정하지 않고 제출하려 할 경우
      • 시간 & 요일 : 시간을 입력해주세요!
      • 시간 : 요일을 입력해주세요!
      • 현재 로직상 요일을 먼저 선택하면 유효성검사를 할수 없으므로 : 시간을 먼저 정해주세요!
      • 날짜가 중복되었을 때 : 테이블 하단에 '이미 예약된 시간입니다' 라는 표시가 생성
      • 삭제할 때 : 정말 삭제하시겠어요? 컨펌이 생성
      • 삭제를 취소했을 때 : 취소되었습니다.
      • 삭제했을 때 : 삭제되었습니다. -> 삭제

기능 상세 설명 : 트러블슈팅

1. Date type을 사용하기

  • 날짜를 사용하여 정렬, 필터 등의 작업을 수행하려고 했지만 Date는 다음과 같은 문제점이 있었습니다.

    • json-server에 저장되는 값과 클라이언트에 불러와졌을때의 문자열 값이 다릅니다. (단순 비교 불가)
    • 두 개를 일치시킬 수는 있지만 정렬시 Date객체를 사용하면 이미 서버 내에 존재하는 데이터에 대해서는 무조건적으로 우선순위가 부여됩니다. 왜냐하면 new Date로 만든 애는 날짜 상으로 새로 만드는 애보다 항상 앞에 있을 거니까요.
  • 게다가 실제 표시되는 데이터 am/pm 시간단위와 24 시간 단위는 간극이 커서 매번 포맷을 돌리기 힘든 구조입니다.

  • Date를 받아와 사용할 경우 : get -> date를 포맷 -> 시간단위로 잘라줌 -> am/pm 포맷으로 다시 만들어줘야함 의 과정이 필요합니다.

  • 그래서 차선책으로 앱 내부에서는 시간을 제작할 때 알맞은 형태로 자르기 위해서만 Date객체를 사용하고 시간들끼리의 비교에 대해서는 철저하게 string[] 대 string[]으로 수행했습니다.

  • 각 데이터는 submit될때 다음과 같은 프로퍼티를 가집니다.

{
  "id": "sdfsd123dfer",
  "tutor": "pika",
  "week": "monday",
  "date" : "2022-07-27T10:00:10.171Z",
"time": ["10:00", "10:40", "am"]},
  • week는 삭제시 url을 찾아갈 때
  • date는 원본 보존용
  • time 배열 안에 있는 3개의 값으로 비교를 수행합니다.
  1. 정렬 시
  • hook/getSort.tsx
  • am/pm을 비교하여 문자열 am가 우선으로 오게 먼저 정렬해주고
  • 1번째 값(start time)을 기준으로 2차 정렬해줍니다.
  1. 필터 시
  • hook/getDate.tsx

  • 사용자가 시간을 선택했을때 해당 시간 -> +40분 동안 발생할 수 있는 모든 경우의 수를 배열로 뽑아줍니다. 즉, 5분 마다의 시간이 표시되는 8개의 문자열을 담은 배열을 만들어 리턴합니다.

  • 이를 timeFilter라고 부르겠습니다.

  • components/selects/Multi.tsx

  • useEffect를 사용해 해당 요일 데이터의 time값과 timeFilter에 대한 비교를 수행합니다.

    • 문제점 : 두 배열의 형태와 길이가 다름
    • 해결 : forEach문을 이중으로 돌려 빠짐없이 모든 경우를 비교하게끔 했습니다.

2. input state의 분리

  • 어차피 간단함을 위해 생략된 형식의 과제라면 더 간단하게 만들어볼 수는 없을까하고 생각해서 ref나 useState로 값을 읽고 저장하는 대신, recoilState를 사용해 보았습니다.

  • input들은 각각 select / dropdown / checkbox 로 사용자의 직접 키보드 입력이 없기 때문에 적용하기 좋은 케이스였습니다.

  • 먼저 각 input form에서 onChange 값을 담는 애들을 전부 분리해서 별개의 component에 담아 은닉하고,

    • am/pm : hooks/useSingleSelect.tsx
    • weeks : hooks/useMultiSelect.tsx
    • time : components/dropdown/Menu.tsx
  • 해당 hook / component 의 useState값을 recoilState로 교체해주고 store/global.ts 에서 전역으로 관리하도록 했습니다.

  • 이렇게 하자 각 폼에서 state를 열심히 모아 submit form에 전달하는 과정이 생략되었기 때문에 코드 양과 데이터 이동을 획기적으로 개선할 수 있었습니다.

  • 컴포넌트들의 추상화단계나 배치도 자유롭게 조절할 수 있게 되었습니다.

3. Data filter의 시점

  • submit 될 때를 시점으로 하자 submit을 누를때마다 유저가 선택한 요일에 대해서 비교작업을 수행해야 했습니다.

  • 여기서 문제점은 요일이 여러개가 될 수 있기에, 저는 weeks를 배열로 만들어서 각 요일의 테이블에 쏴주는 용도로만 사용하게끔 로직을 짰다는 것이었습니다.

    • api model에서 최종적으로 url 파라미터를 끼워넣어 서버에 전달하기 전까지 데이터는 자기가 무슨 요일에 속하는지 모르고 그냥 데이터로만 존재합니다.

      const addSchedule = (week: string[], data: ScheduleProps) => {
        week.map(
          async (week) =>
            week !== "" &&
            (await apiRequest.post(`/${week}`, Object.assign(data, { week }))),
        );
      };
  • 그래서 요일 내 시간 중복을 필터하는 로직을 submit전에 수행할 필요가 있었습니다.

  1. 필요한 데이터

    • 해당 요일이 가지고 있는 시간들에 대한 데이터
    • 현재 유저가 선택하고 있는 시작시간에 대한 데이터
  2. 전제조건

    • 2개의 데이터에 대한 비교를 수행해야 하기 때문에 발동조건을 체크박스를 클릭했을 때로 하는 api요청을 만들었고, 시간을 지정하기 전까지 날짜 체크박스에 대한 사용자 접근을 막았습니다.
  3. 수행

    • 체크박스를 클릭할때마다 전체 데이터를 받아오는 것은 너무 많기도 하고 각 요일마다 타고 들어가서 비교를 수행해주기 까다롭기 때문에 promise.all과 map, selected 배열을 사용하여 각 요청을 동적으로 돌렸습니다.

    • useMultiSelect에서 뿌려주는 selected 배열에는 사용자가 선택한 요일이 배열 형태로 실시간으로 담겨집니다.

    ["monday", "tuesday", "wednesday", "thursday"];
    • 요일별 버튼이 존재하는 components/Multi.tsx에 useEffect를 걸어서 selected에 변화가 있을때마다 map으로 필요한 요청을 보내도록 했습니다.

    • 그리고 그 옆에 useEffect를 하나 더 걸어서 현재 사용자가 선택한 시간과 비교를 수행하도록 했습니다.

    • 자세한 내용은 1번과 겹치므로 생략하겠습니다.

  4. 아쉬운 점

    • 체크박스를 트리거로 사용했기에 만약 날짜에 중복이 발생해서 멈춘 후에는, 체크박스를 한번 클릭해서 초기화 시켜주는 작업이 필요합니다.
    • 사용자 입장에서는 중복이다 -> 다른거 클릭했는데 왜 안돼 하는 상황이 종종 발생하는 것입니다.
    • 이를 보완하기 위해 초기화하기라는 버튼을 따로 제작해서 클릭할 수 있게 하거나 validation 버튼을 따로 만들어서 사용자가 원하는 시점에 검사를 수행할 수 있게 하는 등의 로직 개선을 고민 중에 있습니다.

4. 회고

  • typeScript의 타입, api 구성, 비동기문법의 사용, 배열과 객체에 대한 반복로직 작성 등, 기본기를 튼튼하게 점검하고 공부할 수 있는 좋은 과제였던 것 같습니다.
  • any의 사용을 더 줄이고 각 데이터타입의 특성을 고려하여 코드를 짜야겠다고 생각했습니다.

About

원티드 프리온보딩 기업과제 Week-4-2 Schedule

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published