Salangdung_i의 기록

[ 팀 프로젝트 ] 수업 일정 페이지 과제 후기 본문

개발/2022_회고

[ 팀 프로젝트 ] 수업 일정 페이지 과제 후기

Salangdung_i 2022. 8. 14. 12:40
728x90
프로젝트 회고

 

원티드 프리온보딩 프론트엔트 코스에서 진행한 수업 일정 페이지 과제 후기이다. 7월 28일부터 30일까지 3일간 잉그올의 기업과제를 만들어 보았다.

 

 

프로젝트 기간은 3일지 이만 발표가 있는 토요일은 10시부터 세션이 시작하기에 사실상 개발기간은 2일이었다. 원래는 개인 프로젝트였지만 결국 팀 단위로 제출하는 프로젝트이기에 제출하는 결과물은 하나여야 한다. 멘토님께서 팀원 중 가장 잘된 결과물을 리팩터링 해서 제출하거나, 각자 구현하고 잘된 부분을 따와서 합치거나, 아예 기능을 나누어서 개발해도 된다고 하셨다. 

그동안 프로젝트를 해본 결과 우리 팀의 기능 구현에는 문제가 없었다. 그렇다면 중요한 것은 코드 퀄리티와 지금까지 해보지 못한 핵심기능인 수업 일정 추가 시 이미 추가된 일정이면 추가를 방지하는 로직 구현이었다. 

과제의 난이도가 어려운 것은 아니지만 짧은 시간이 였기에 가장 효율적인 방법은 무엇인가를 고민했고 어렵지 않지만 시간을 많이 잡아먹는 UI 작업과 초기 세팅(라우터, 레이아웃)을 먼저 작업하고 나머지를 팀원들과 나눠서 작업하는 건 어떨까 생각이 들었다. 수요일 세션이 끝나고 과제 설명한 이후부터 다음날 팀원들과 회의를 하기 전까지 내가 처리한 작업은 

[1]  전체 페이지 (수업 보기, 추가 페이지) 레이아웃, 라우터, UI 작업
[2]  재사용 가능한 카드, 버튼 공통 컴포넌트 작업

 

 이었다.

다행이 내가 작업한 프로젝트에 팀원들이 긍정적인 반응을 보였고, 나머지 기능을 팀원들이 구현하는 것으로 방향을 잡았다. 

 

 

구현 시 신경 쓴 부분

 

1. 공통 컴포넌트 구현

그동안 팀 프로젝트를 진행하면서 빠른 UI 작업을 위해 MUI 라이브러리를 많이 사용하였다. 내가 현업을 했을 때도 빠른 작업을 위해 Vuetify를 사용했는데 기획자의 요구사항에 맞게 커스텀하는 것에 한계를 느꼈다. 그래서 매번 하는 말이 "일단 빠르게 Vuetify로 작업하고 나중에 다 걷어내고 새로 만듭시다." 였기에 UI 라이브러리를 최대한 지양하고자 했다. 이러한 이유로 공톰 컴포넌트로 카드와 버튼을 만들었다.  

 ┣── 📂components
 ┃ ┣── cButton.tsx
 ┃ ┗── cCard.tsx

Common의 앞글자만 뺴서 공통 컴포넌트에는 C를 붙여주었다. 

import React from 'react';
import styled from 'styled-components';

interface ButtonProps {
  name: string;
  onClick: () => void;
}

export default function CButton({ name, onClick }: ButtonProps) {
  return <Button onClick={onClick}>{name}</Button>;
}

const Button = styled.button`
  background-color: #1a6ace;
  color: #fff;
  outline: 0;
  border: 0;
  border-radius: 5px;
  width: fit-content;
  padding: 0 20px;
  height: 35px;
  &:hover {
    cursor: pointer;
  }
`;
import React from 'react';
import { ServerSideSchedule } from '../types';
import ClearIcon from '@mui/icons-material/Clear';
import styled from 'styled-components';
import { string24ToString12 } from '../utils/dateTimeHelper';

interface cCardProps {
  lecture: ServerSideSchedule;
  onClick: (id: number) => void;
}

function cCard({ lecture, onClick }: cCardProps) {
  const { id, start, end } = lecture;

  const startTime = string24ToString12(start);
  const endTime = string24ToString12(end);

  return (
    <Container>
      <Times>
        <Time>{startTime} -</Time>
        <Time>{endTime}</Time>
      </Times>
      <StyledClearIcon sx={{ fontSize: 11 }} onClick={() => onClick(id)} />
    </Container>
  );
}

export default cCard;

const Container = styled.div`
  margin: 6px 0;
  padding: 6px;
  border-radius: 4px;
  background-color: #efeeef;
  display: flex;
  gap: 4px;
  flex-direction: row;
`;
const Times = styled.div``;
const Time = styled.div`
  color: #747474;
`;
const StyledClearIcon = styled(ClearIcon)`
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #b4b4b4;
  color: #efeeef;
  border-radius: 50%;
  cursor: pointer;
`;

 

2. 라우터 

처음 코스에 참가 했을 때 리액트 라우터에 대해 얕은 지식이 있었다. (페이지 이동을 하는 기능을 하며 Routes로 Route를 감싸서 path와 element를 지정한다 정도로 알고 있었다.) 부하는 기간에 react router 공식 문서에서 Tutorial을 공부하였다. 👉 공부한 repo  유용하게 사용한 기능은 Outlet이다.

공식문서 발췌

레이아웃 설정에 사용하는데, 중첩 라우팅의 구성이 되면  Outlet를 사용해서  상위 컴포넌트를 레이아웃화 할 수 있다. outlet에 Main 또는 Add 페이지가 들어간다. 

 

3. 이미 수업이 있을 경우 수업 추가를 막는 기능

요구사항 중에 add class schedule 버튼을 눌렀을 때 이전의 수업 스케줄과 겹친다면 추가가 되지 않는 기능이 정의되어있었다. 팀원들과 어떻게 하면 UX적으로 더 편리할 수 있을까 고민하다 시간을 선택했을 때 이전 수업 스케줄과 겹친다면 요일이 비활성화돼서 선택하지 못하게 기능 구현하는 것으로 결정했다.  

아래는 실제 구현한 화면이다.  

 

스케줄을 확인하는 함수를 따로 구현했다.

export function checkSchedules(
  totalSchedules: ServerSideScheduleWrapper,
  selectedSchedule: {
    start: Date;
    end: Date;
  },
) {
  const unavailableDays = [];
  const { start, end } = selectedSchedule;
  const weeks = Object.keys(totalSchedules);
  for (const day of weeks) {
    const daySchedules = totalSchedules[day];
    for (const daySchedule of daySchedules) {
      const { start: dayStart, end: dayEnd } = daySchedule;
      const dayStartObj = string24ToObject(dayStart);
      const dayEndObj = string24ToObject(dayEnd);

      if (compareAsc(start, dayStartObj) === 1) {
        if (compareAsc(start, dayEndObj) === -1) {
          unavailableDays.push(day);
          break;
        }
      }
      if (compareAsc(end, dayStartObj) === 1) {
        if (compareAsc(end, dayEndObj) === -1) {
          unavailableDays.push(day);
          break;
        }
      }
      if (start.getHours() === dayStartObj.getHours()) {
        if (start.getMinutes() === dayStartObj.getMinutes()) {
          unavailableDays.push(day);
          break;
        }
      }
    }
  }
  return unavailableDays;
}

내가 짠 코드는 아니였지만 팀원 분이 짠 코드였고, 우리 팀은 맡은 기능 구현이 끝나면 PR을 올리고, 모든 팀원이 읽고 코드 리뷰를 남기거나 승인을 해야 main 브랜치에 merge 하기에 이 코드를 유심히 보았다.

코드 설명을 간략하게 하면,

compareAsc는 date fns에서 제공하는 함수인데 compareAsc(date1, date2) 두 날짜를 비교해서 첫번쨰 날짜가 두 번째 날짜 이후면 1을 반환, 같으면 0 이전이면 -1을 반환한다. 

수업을 시작하려는 시간과 끝시간을 받고 이전에 계획된 수업들을 시간을 비교해서 시간 사이에 껴있다면 해당 요일을 unavailableDays 배열에 담고 이를 반환하는 함수이다. 이로써 수업을 추가할 수 없는 요일을 비활성 화 할 수 있다. 

 

 

후기

 

주어진 프로젝트 기간이 2일으로 너무 짧아서 과제의 난이도보다 체감 난이도가 더 높게 느껴진 과제였다. 비슷한 알고리즘 문제를 받아 본 적이 있었는데 그때는 풀지 못했었다. 멘토님이 date fns 라이브러리에 시간을 비교하는 함수가 있다고 언급해주셨는데 시간을 다루는 로직을 짤 때, 앞으로도 유용하게 사용할 거 같아서 또 하나 배웠고 생각했다. 이 프로젝트를 발표할 때 우리 팀원이 테스트 시나리오와 트러블 슈팅 과정들을 정리해서 발표하였는데 다른 팀의 발표보다 듣기 쉬웠다. 정보 전달하는 스킬을 하나 배웠다. 

728x90