과제 리뷰2

김영준·2020년 10월 4일
0

과제

목록 보기
1/3
post-thumbnail
  1. src/View/Main/MainView.js

이제 MainView 를 살펴보겠다.

import React, { useState } from "react";
import Modal from "../../components/Modal/Modal";
import Calender from "../../components/Calender/Calender";
import HourSelector from "../../components/HourSelector/HourSelector";
import MinuteSelector from "../../components/MinuteSelector/MinuteSelector";
import Divider from "../../components/Divider/Divider";
import "./index.scss";

const MainView = (props) => {
  const [visible, setVisible] = useState(false);
  // modal을 보여줄지 말지 결정.
  const [calender, setCalender] = useState(false);
  // calender 가 start 인지 finish 인지 상태를 담고있음.
  const _showDate = () => {
    // 날짜가 모두 선택되고 난 뒤, 보여지는 내용
    if (props.date !== undefined) {
      const {
        startDay,
        startMinute,
        startHour,
        finishDay,
        finishMinute,
        finishHour,
      } = props.date;
      return (
        <>
          <div>응시 시작일 : {startDay ? startDay : "선택해주세요."}</div>
          <div>
            응시 시간 : <span>{startHour ? startHour : "미정"}</span>&nbsp;
            <span>{startMinute ? startMinute : "미정"}</span>
          </div>
          <div>응시 마감일 : {finishDay ? finishDay : "선택해주세요."}</div>
          <div>
            응시 마감시간 : <span>{finishHour ? finishHour : "미정"}</span>
            &nbsp;<span>{finishMinute ? finishMinute : "미정"}</span>
          </div>
        </>
      );
    } else {
      return;
    }
  };
  return (
    <div>
      <button className="call-modal" onClick={() => setVisible(!visible)}>
        모달호출
      </button>
      <Modal
        visible={visible}
        setCalender={(e) => setCalender(e)}
        setVisible={(e) => setVisible(e)}
        date={props.date}
      >
        <br />
        <div className="date-txt">응시 시작일</div>
        <br />
        <input
          className="date-picker start"
          readOnly
          placeholder="날짜를 선택해 주세요."
          value={props.date && props.date.startDay}
          style={{
            backgroundColor: props.date && props.date.startDay ? "#efefef" : "",
          }}
          onClick={() => setCalender("start")}
        />
        {calender === "start" && (
          <Calender
            {...props}
            status={"start"}
            setCalender={(e) => setCalender(e)}
          />
        )}
        <HourSelector status="start" {...props} />
        <MinuteSelector status="start" {...props} />
        <Divider margin={"0 0 40px 0"} height="40px" />

        <div className="date-txt">응시 마감일</div>
        <br />
        <input
          className="date-picker finish"
          readOnly
          placeholder="날짜를 선택해 주세요."
          value={props.date && props.date.finishDay}
          style={{
            backgroundColor:
              props.date && props.date.finishDay ? "#efefef" : "",
          }}
          onClick={() => setCalender("finish")}
        />
        {calender === "finish" && (
          <Calender
            {...props}
            status="finish"
            setCalender={(e) => setCalender(e)}
          />
        )}
        <HourSelector {...props} />
        <MinuteSelector {...props} />
      </Modal>
      <div className="result" style={{ display: visible ? "none" : "block" }}>
        {_showDate()}
      </div>
    </div>
  );
};

export default MainView;
  1. visible 은 모달이 보여질지 말지 관리하는 변수이다.
  2. calender는 calender 창이 보여질지 말지 관리하는 변수.
  3. _showDate 는 날짜가 모두 선택되어지고 보여질 글씨를 리턴하는 함수이다. (중요X)
  4. 제일 먼저 <Modal> 컴포넌트로 감싸져 있다. 이 Modal Component 는 props 로 visible, setVisible, setCalender , date 를 받는다.
    들어가는 내용 content 는 children 으로 받게 된다.
  5. 내부에 컴포넌트로 Calender,HourSelector,MinuteSelector가 들어간다.

  1. src/components/Calender/Calender.js
import React, { useState } from "react";
import moment from "moment";
import "./index.scss";

const Calender = (props) => {
  const [select, setSelect] = useState(null);
  const [choiceMonth, setChoiceMonth] = useState(moment());
  // * 1. 현재 시간을 choiceMonth 로 설정함.
  const dayname = () => {
    let labels = [];
    for (let i = 1; i <= 7; i++) {
      let dayOfWeek = moment().day(i).format("dd");
      if (dayOfWeek === "Mo") {
        dayOfWeek = "월";
      } else if (dayOfWeek === "Tu") {
        dayOfWeek = "화";
      } else if (dayOfWeek === "We") {
        dayOfWeek = "수";
      } else if (dayOfWeek === "Th") {
        dayOfWeek = "목";
      } else if (dayOfWeek === "Fr") {
        dayOfWeek = "금";
      } else if (dayOfWeek === "Sa") {
        dayOfWeek = "토";
      } else if (dayOfWeek === "Su") {
        dayOfWeek = "일";
      }

      labels.push(
        <div className="label" key={i}>
          {dayOfWeek}
        </div>
      );
    }
    return labels;
  };
  const _dayClick = (date) => {
    setSelect(date);
    let finishStoreData = Object.assign({}, props.date, { finishDay: date });
    let startStoreData = Object.assign({}, props.date, { startDay: date });
    let storeData = props.status === "start" ? startStoreData : finishStoreData;
    props.viewAction.receiveView("date", storeData);
  };
  const generate = () => {
    const today = choiceMonth;
    const startWeek = today.clone().startOf("month").week();

    // clone 을 하는 이유 : moment 객체가 변할 수 있는(mutable) 성질이 있어서 해당 시간 고정을 위해 clone 사용함.

    // * startWeek : 현재월의 첫번째날이 몇번째 주 인지
    const endWeek =
      today.clone().endOf("month").week() === 1
        ? 53
        : today.clone().endOf("month").week();
    // * endweek : 현재월의 마지막달이 몇번째 주 인지
    let calendar = [];
    for (let week = startWeek; week <= endWeek; week++) {
      calendar.push(
        <div className="day-row" key={week}>
          {Array(7)
            .fill(0)
            .map((n, i) => {
              let current = today
                .clone()
                .week(week)
                .startOf("week")
                .add(n + i, "day");
              // * current : for문에 있는 week 의 day를 담고 있는 변수
              let isToday =
                moment().format("YYYYMMDD") === current.format("YYYYMMDD")
                  ? "today"
                  : "";
              // * isToday : moment의 현재날짜와 current 가 가지고 있는 현재날짜가 같으면 today 를 담고있음.
              let isGrayed =
                current.format("MM") === today.format("MM") ? "" : "grayed";
              // * current 의 month 와 today의 month 가 같으면 "" 다르면 grayed 라는 변수 담고 있음.
              let isSelectDay =
                select === current.format("YYYY-MM-DD") ? "choice" : "";
              // * 선택한 날짜와 current 가 같으면 choice 라는 변수를 담고있음.
              return (
                <div key={i} className="day-col">
                  <div
                    onClick={
                      () =>
                        _dayClick(
                          current
                            .clone()
                            .add(n + 1, "day")
                            .toISOString()
                            .split("T")[0]
                        )
                      // 클릭할 때 선택한 날의 YYYY-MM-DD 를 넘김
                    }
                    className={`box ${isToday} ${isSelectDay} ${isGrayed}`}
                  >
                    {current.format("D")}
                  </div>
                </div>
              );
            })}
        </div>
      );
    }
    return calendar;
  };

  // console.log(props);
  return (
    <div className="calender-wrapper">
      <div className="month-row">
        <span style={{ fontWeight: "bold" }}>
          {choiceMonth.format(
            "YYYY MM".split(" ")[0] +
              "년" +
              " " +
              choiceMonth.format("YYYY MM").split(" ")[1] +
              "월"
          )}
        </span>
        <span>
          <span
            onClick={() =>
              setChoiceMonth(choiceMonth.clone().subtract(1, "month"))
            }
            className="arrow"
            style={{ marginRight: 20 }}
          >
            <img src={require("../../img/btn-arrow-back.png")} alt="" />
          </span>
          <span
            onClick={() => setChoiceMonth(choiceMonth.clone().add(1, "month"))}
            className="arrow"
          >
            <img src={require("../../img/btn-arrow-front.png")} alt="" />
          </span>
        </span>
      </div>
      <div className="day-row">
        {dayname().map((day, idx) => (
          <div key={idx} className="day-col">
            {day}
          </div>
        ))}
      </div>
      {generate()}
    </div>
  );
};

export default Calender;
  • 우선 dayname 함수는 영어로 된 요일 이름을 한글로 바꾸기 위해 사용함.

  • _dayClick 함수는 날짜를 선택했을 때 store 에 저장하기 위해 사용함.

  • generate 함수 : 설명이 길어서 주석으로 설명을 대체함.

  • ./calender.scss 내용을 첨부함. (클래스 이름에 따라 색 변경)

.calender-wrapper {
  width: 300px;
  border-radius: 10px;
  background-color: #f9f9f9;
  padding: 10px;
  position: absolute;
  z-index: 200;
  .month-row {
    display: flex;
    justify-content: space-between;
    margin: 15px 0;

    .arrow {
      text-align: center;
      font-size: 20px;
      width: 25px;
      line-height: 1.5;
      height: 25px;
      display: inline-block;
      cursor: pointer;
      border-radius: 15px;
      background-color: #dbdbdb;
      opacity: 0.3;
    }
    .arrow:hover {
      transition: 0.3s all ease;
      opacity: 0.6;
    }
  }

  .day-row {
    display: flex;
    justify-content: space-between;
    margin-bottom: 1px;
    .day-col {
      text-align: center;
      position: relative;
      display: inline-flex;
      width: calc(100% / 7);
      height: 50px;
      font-size: 12pt;
      .box {
        display: inline-block;
        margin: auto;
        width: 25px;
        height: 25px;
        line-height: 1.7;
        cursor: pointer;
        border-radius: 13px;
        &.today {
          background-color: #dbdbdb;
          // today 면
        }
        &.grayed {
          color: darkgray;
          // 이번달이 아니면 회색 처리
        }
        &.choice {
          background-color: #4c80f1;
          color: #fff;
          // 선택한 날이면 배경색 변경 및 글짜 색 흰색
        }
        &.choice:hover {
          background-color: #2263f0;
          color: #fff;
          // 선택한 날에 마우스 hover
        }
      }
      .box:hover {
        color: #4c80f1;
        background-color: #93b5ff;
      }
      .label {
        display: inline-block;
        margin: auto;
      }
    }
  }
}

코드양이 길어져 selectHour 부분은 다음 포스팅에 이어서작성

profile
프론트엔드 개발자 김영준 입니다. 디테일함을 키우고 있습니다

0개의 댓글