[탐나예] 예약 현황 페이지

AnSuebin·2022년 10월 7일
0

[탐나예]프로젝트

목록 보기
3/4

탐나예 예약 현황 페이지 기능 및 코드 소개
1. 예약 현황 페이지 간단 기능 소개
2. 코드 소개

00. 들어가기 전에

  • 예약 현황 페이지는 프로젝트를 풍성하게 하기 위해 추가된 페이지입니다.
  • 우선적으로 표 내에 예약 시간, 회의실에 맞게 잘 예약이 표현 되는 것을 중심으로 형태를 구현하였습니다. 또한, 팝업창을 사용하여 예약 현황 세부내역을 구현하도록 하였습니다.
  • React를 기반으로 제작하였습니다.

01. 예약 현황 페이지 간단 기능 소개

  • 한 페이지에서 하루 전체 예약 현황 확인
  • 매니저 권한 예약은 공식일정으로 노출
  • 예약 내용 클릭 시 팝업창으로 세부 예약 내용 확인 가능

02. 코드 소개

2-1.예약현황 메인페이지에서 유저별 층수 데이터 전송

  • 메인 페이지와 마찬가지로, 컴포넌트는 2층을 보여주는 페이지, 3층을 보여주는 페이지, 2,3,4층을 모두 보여주는 페이지로 구성되어 있습니다.
  • ReservationState 라는 페이지를 통해 유저 데이터를 받아, 관련 데이터를 구분하였고, props를 활용해 할당해주었습니다.

2-1-1) useState로 각 데이터 선언

  //층수 API 정보 가져오기
  const [floor, setfloor] = useState('');
  const [bookingData, setBookingData] = useState([]);
  const [roomData, setRoomData] = useState([]);

  // 2층 정보
  const [SecondMeetingRoominfo, setSecondMeetingRoominfo] = useState([]);
  const [SecondNaboxinfo, setSecondNaboxinfo] = useState([]);
  const [SinyangID, setSinYangID] = useState('');
  const [SinyangName, setSinYangName] = useState('');

  // 3층 정보
  const [ThirdMeetingStudioinfo, setThirdMeetingStudioinfo] = useState([]);
  const [ThirdNaboxinfo, setThirdNaboxinfo] = useState([]);

  // 4층 정보
  const [FourthFloorinfo, setFourthFloorinfo] = useState([]);

2-1-2) fetch, get을 통해 백에서 데이터를 층수에 맞게 구분 한 후, 필터로 세부 룸에 대한 정보로 나누기

 const myUrl = useUrl();
  const url = `http://${myUrl}/api/booking/details-booking`;
  const navigate = useNavigate();
  useEffect(() => {
    fetchGet(url, navigate).then((data) => {
      setfloor(data.floor);
      setBookingData(data.BookingData);
      setRoomData(data.RoomData);

      // 2층 일 때 정보
      if (data.floor === 2) {
        setSecondMeetingRoominfo(
          data.RoomData.filter(
            (rooms) =>
              rooms.roomType === 'meeting' && rooms.roomType !== 'official'
          )
        );
        setSecondNaboxinfo(
          data.RoomData.filter((rooms) => rooms.roomType === 'nabox')
        );
        setSinYangID(
          data.RoomData.filter((rooms) => rooms.roomType === 'official')[0]
            .roomId
        );
        setSinYangName(
          data.RoomData.filter((rooms) => rooms.roomType === 'official')[0]
            .roomName
        );
      }

      // 3층 일 때 정보
      else if (data.floor === 3) {
        setThirdMeetingStudioinfo(
          data.RoomData.filter(
            (rooms) =>
              rooms.roomType === 'meeting' || rooms.roomType === 'studio'
          )
        );
        setThirdNaboxinfo(
          data.RoomData.filter((rooms) => rooms.roomType === 'nabox')
        );
      }

      // 0층일 때 즉 모두 보여줘야 할 때 정보
      else {
        // 2층 정보
        setSecondMeetingRoominfo(
          data.RoomData.filter(
            (rooms) =>
              rooms.floor === 2 &&
              rooms.roomType === 'meeting' &&
              rooms.roomType !== 'official'
          )
        );
        setSecondNaboxinfo(
          data.RoomData.filter(
            (rooms) => rooms.floor === 2 && rooms.roomType === 'nabox'
          )
        );
        setSinYangID(
          data.RoomData.filter((rooms) => rooms.roomType === 'official')[0]
            .roomId
        );
        setSinYangName(
          data.RoomData.filter((rooms) => rooms.roomType === 'official')[0]
            .roomName
        );
        // 3층 정보
        setThirdMeetingStudioinfo(
          data.RoomData.filter(
            (rooms) =>
              (rooms.floor === 3 && rooms.roomType === 'meeting') ||
              rooms.roomType === 'studio'
          )
        );
        setThirdNaboxinfo(
          data.RoomData.filter(
            (rooms) => rooms.floor === 3 && rooms.roomType === 'nabox'
          )
        );
        // 4층 정보
        setFourthFloorinfo(data.RoomData.filter((rooms) => rooms.floor === 4));
      }
    });
  }, [url, myUrl]);

2-1-2) !!! 여기서 중요한 포인트 !!!

  • floor가 0일 때 => 모든 정보를 보여줘야합니다.
  • 따라서, 그 내부에서 room.floor를 구분하고, 회의실, 나박스를 추가로 구분해주어야합니다.
  • 2층 예시 🔻
      else {
        // 2층 정보
        setSecondMeetingRoominfo(
          data.RoomData.filter(
            (rooms) =>
              rooms.floor === 2 &&
              rooms.roomType === 'meeting' &&
              rooms.roomType !== 'official'
          )
        );
        setSecondNaboxinfo(
          data.RoomData.filter(
            (rooms) => rooms.floor === 2 && rooms.roomType === 'nabox'
          )
        );
        setSinYangID(
          data.RoomData.filter((rooms) => rooms.roomType === 'official')[0]
            .roomId
        );
        setSinYangName(
          data.RoomData.filter((rooms) => rooms.roomType === 'official')[0]
            .roomName
        );

2-1-3) props를 통해 층수 별 component에 정보 할당하기

 {floor === 0 && [
        <AllFloorReservationState
          className={styles.reservationTable}
          key="0"
          SecondMeetingRoominfo={SecondMeetingRoominfo}
          SecondNaboxinfo={SecondNaboxinfo}
          ThirdMeetingStudioinfo={ThirdMeetingStudioinfo}
          ThirdNaboxinfo={ThirdNaboxinfo}
          FourthFloorinfo={FourthFloorinfo}
          bookingData={bookingData}
          roomData={roomData}
          SinyangID={SinyangID}
          SinyangName={SinyangName}
          floor={floor}
        />,
      ]}
      {floor === 2 && [
        <SecondFloorReservationState
          key="2"
          className={styles.reservationTable}
          SecondMeetingRoominfo={SecondMeetingRoominfo}
          SecondNaboxinfo={SecondNaboxinfo}
          bookingData={bookingData}
          roomData={roomData}
          SinyangID={SinyangID}
          SinyangName={SinyangName}
          floor={floor}
        />,
      ]}
      {floor === 3 && [
        <ThirdFloorReservationState
          key="3"
          className={styles.reservationTable}
          ThirdMeetingStudioinfo={ThirdMeetingStudioinfo}
          ThirdNaboxinfo={ThirdNaboxinfo}
          bookingData={bookingData}
          roomData={roomData}
        />,
      ]}

2-2. 층수별로 보이는 페이지를 구분하여 제작

  • 층수별로 구분하여 페이지를 제작하였고, 그 내에서 회의실과 나박스 버튼을 구분하여, 클릭 시 각각의 정보가 보이도록 제작하였습니다.

2-2-1) 3층 컴포넌트 예시 / state로 현재 보여주는 회의실 타입 구분

const [RoomType, setRoomType] = useState(true);
  const MeetingRoom = true;
  const NaBox = false;

2-2-2) 회의실 버튼, 나박스 버튼 클릭 함수 설정

  const MeetingRoomOnClick = () => {
    setRoomType(MeetingRoom);
  };
  const NaboxOnClick = () => {
    setRoomType(NaBox);
  };
  
  return (
    <div>
      <div className={styles.ReservationStateContainer}>
        {/* 3층 나박스와 회의실 버튼 */}
        <div className={styles.buttonContainer}>
          <button className={styles.button} onClick={MeetingRoomOnClick}>
            회의실
          </button>
          <button className={styles.button} onClick={NaboxOnClick}>
            Na Box
          </button>
        </div>

2-2-3) state 사용하여, 아래에 정보 뿌리기

         {RoomType ? (
            <ThirdFloorMeetingRoomState
              className={styles.reservationTable}
              ThirdMeetingStudioinfo={ThirdMeetingStudioinfo}
              bookingData={bookingData}
              roomData={roomData}
            />
          ) : (
            <ThirdFloorNaRoomState
              className={styles.reservationTable}
              ThirdNaboxinfo={ThirdNaboxinfo}
              bookingData={bookingData}
              roomData={roomData}
            />
          )}

2-3. 예약 관련 데이터, 표에 뿌리기

  • 표의 디자인은 부트스트랩을 활용하여 제작하였습니다.

2-3-1) 해당 시간과 룸에 예약이 있는지 확인하는 함수 설정
1) 시간당 룸에 예약 데이터 불러오는 함수 설정

  • room의 이름이 같고
  • 시작 시간과 시간이 같은 것이 있
  const TimeAndRoomFilter = (Time, Room) => {
    let timedata = bookingData.filter(
      (room) =>
        room.roomId === Room && TimeToString(room.startTime) === onlyTime(Time)
    );
    return timedata;
  };

2) 시간당 룸의 예약이 있는지 확인하는 함수 설정

  const IsThisTimeRoombooked = (Time, Room) => {
    const IsTrue = TimeAndRoomFilter(Time, Room).length !== 0;
    return IsTrue;
  };

3) 예약 시간 구하는 함수 설정

  const bookingLength = (startTime, endTime) => {
    let length =
      Number(TimeToString(endTime)) - Number(TimeToString(startTime));
    return length;
  };

2-3-2) 룸의 값은 map으로 돌려, 행으로 뿌려주었고, Link를 사용해 예약으로 관련 룸 예약으로 들어갈 수 있도록 제작하였습니다.

<thead className="table-light" id={styles.thead}>
    <tr id={styles.theadTr}>
        <th className="table-primary text-break" id={styles.time}></th>
            {/* 룸 값 불러오기 */}
            {ThirdNaboxinfo.map((room) => (
              <th key={room.roomId} className="table-primary" id={styles.text}>
                <Link to={`/booking/${room.roomId}`} id={styles.roomA}>
                  <ArrowRightCircleFill />
                  &nbsp;
                  {room.roomName}
                </Link>
              </th>
            ))}
    </tr>
</thead>

2-3-3) 시간 맵을 돌리고, 그 안에서 한번더 관련 룸의 값을 맵으로 돌려 테이블에 예약된 것이 알맞는 위치에 들어갈 수 있도록 하였습니다.
1) 시간 맵 돌리기

 {timeList.map((time) => (
            <tr key={time} id={styles.tbodyTr}>
              <th className={styles.time}>{time}</th>

2) 그 내부에 시간에 맞는 회의실 예약 상황을 전달
- 함수를 통해 예약이 있는지 확인, 있으면 버튼과 팝업 창, 없으면 null

{ThirdNaboxinfo.map((room) => (
     <th key={room.roomId} className={styles.roomstate}>
         {IsThisTimeRoombooked(time, room.roomId) ? (
               <OverlayTrigger>
               </OverlayTrigger>
          ) : null}
     </th>
))}

3) 팝오버 부트스트랩 사용, 관련 예약 내용 props로 전달

<OverlayTrigger
    trigger={['hover', 'focus']}
    key={TimeAndRoomFilter(time, room.roomId)[0].bookingId}
    placement="top"
    overlay={
        <Popover id="popover-positioned-top">
              <Popover.Body>
                     <PoplayNabox
                      userName={
                        TimeAndRoomFilter(time, room.roomId)[0]
                       .applicant.userName
                      }
                      startTime={
                        TimeAndRoomFilter(time, room.roomId)[0]
                           .startTime
                       }
                      endTime={
                        TimeAndRoomFilter(time, room.roomId)[0].endTime
                      }
                      roomName={
                         TimeAndRoomFilter(time, room.roomId)[0].roomName
                      }
                      />
                </Popover.Body>
           </Popover>
   }
>

4) 버튼 스타일 높이는 bookingLength()의 숫자에 표 높이를 곱한 수로 설정
5) 아이디는 official이라면 매니저 스타일로 따로 적용
6) 버튼 내부에 userName 포함

<button
     style={{
         height: `${
                 bookingLength(
                       TimeAndRoomFilter(time, room.roomId)[0].startTime,
                       TimeAndRoomFilter(time, room.roomId)[0].endTime
                  ) * 35.4
          }px`,
      }}
     className={styles.bookingTime}
     id={
          TimeAndRoomFilter(time, room.roomId)[0].official
                  ? [styles.Manager]
                  : null
     }
                        variant="secondary"
>
     <p>
           <EmojiSmileFill />
           &nbsp;&nbsp;
           {
                  TimeAndRoomFilter(time, room.roomId)[0].applicant
                         .userName
            }
            님 예약
       </p>
</button>
profile
고객에게 명료한 의미를 전달하고, 명료한 코드를 통해 생산성 향상에 기여하고자 노력합니다.

0개의 댓글