프로젝트/호텔 검색 앱

호텔 검색 앱 7 - 호텔 객실 상세정보 보기 구현하기

syleemomo 2021. 12. 21. 22:42
728x90

 

* 호텔 객실 정보를 보여주기 위한 모달창 추가하기

components 폴더 하위에 아래 파일들을 추가한다.

import React from 'react'
import './Modal.css'

function Modal({ open, children }){
    return <div className={`Modal-container ${open? "open": "close"}`}>
                <div className={`Modal`}>{children}</div>
            </div> 
}

export default Modal;

Modal.defaultProps = {
    open: false
}

Modal.js 파일을 생성하고 위와 같이 작성하자!

.Modal-container{
    width: 100%;
    height: 100%;
    background-color: rgba(77, 73, 73, 0.7);

    position: fixed;
    overflow: hidden;
    display: none;
    top: 0;
    left: 0;
}
.Modal {
    width: calc(100% - 128px);
    max-width: 1200px;
    height: 700px;
    background: white;
    color: black;
    font-weight: bold;
    border-radius: 8px;
    
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    text-align: center;
    z-index: 1;

    overflow: hidden;
}
.open{
    display: block;
}
.close{
    display: none;
}

Modal.css 파일을 생성하고 위와 같이 작성하자!

export { default as Input } from './Input'
export { default as Button } from './Button'
export { default as Caption } from './Caption'
export { default as HotelItem } from './HotelItem'
export { default as Accordion } from './Accordion'
export { default as AccordionItem } from './AccordionItem'
export { default as StarRatingFilter } from './StarRatingFilter'
export { default as Review } from './Review'
export { default as Room } from './Room'
export { default as Modal } from './Modal'

components > index.js 파일에 Modal 컴포넌트를 추가로 내보낸다.

 

* Room 컴포넌트에서 모달창에 객실 세부정보 보여주기

import React, { useState } from 'react'
import { isArrayNull, handleNullObj } from 'lib'
import { Modal } from 'components'

import './Room.css'

const Room = ({ room }) => {
    // console.log('Room:', room)

    const { images, name, maxOccupancy, ratePlans, additionalInfo } = handleNullObj(room)
    const { messageTotal, messageChildren } = handleNullObj(maxOccupancy)
    const { description, details } = handleNullObj(additionalInfo)
    const { amenities } = handleNullObj(details)

    const [open, setOpen] = useState(false)

    const controlScrollbar = (control) => {
        document.documentElement.style.overflow = control
    }

    const showAdditionalRoomInfo = () => {
        controlScrollbar('hidden') // 스크롤바 숨기기
        setOpen(true)
    }
    const hideAdditionalRoomInfo = () => {
        controlScrollbar('') // 스크롤바 보여주기
        setOpen(false)
    }
    const RoomThumbnail = () => {
        return (
            <div className='Room-thumbnail'>
                <img src={!isArrayNull(images) && images[0].thumbnailUrl}/>
            </div>
        )
    }
    const RoomInfo = () => {
        return (
            <div className='Room-info'>
                <div className='Room-name'>{name}</div>
                <div className='Room-max-occupancy'>{messageTotal}<br/>{messageChildren}</div>
                <div className='Room-more-info' onClick={showAdditionalRoomInfo}>객실 정보 보기</div>
            </div>
        )
    }
    const RatePlan = ({ ratePlan }) => {
        const { cancellations, features, welcomeRewards, price } = handleNullObj(ratePlan)
        const { current, info, totalPricePerStay } = handleNullObj(price)
        const totalPrice = totalPricePerStay? totalPricePerStay.split(/[<>()]/) : []
        
        return (
            <div className='Room-rateplan'>
                <Modal open={open}>
                    <div className='Modal-header'>
                        <div className='Modal-close' onClick={hideAdditionalRoomInfo}>X</div>
                        <div className='Modal-room-type'>{name}</div>
                    </div>
                    <div className='Modal-body'>
                        <div className='Modal-thumbnail-container'>
                            <div className='Modal-thumbnail'>
                                <img src={images[0].fullSizeUrl} alt='Modal-room-thumbnail'/>
                            </div>
                            <div className='Modal-maxOccupancy'>{messageTotal} {messageChildren}</div>
                        </div>
                        <div className='Modal-room-amenity' dangerouslySetInnerHTML={{ __html: description }}></div>
                        <div className='Modal-room-facility'>
                            <div className='Modal-room-details-text'>객실 세부 정보</div>
                            <div className='Modal-room-details'>{!isArrayNull(amenities) && amenities.map( (amenity, id) => {
                                return (
                                    <li key={id}>{amenity}</li>
                                )
                            })}</div>
                        </div>
                    </div>
                </Modal>
                <div className='Room-features'>
                    <div className='Room-features-title'>{!isArrayNull(cancellations) && handleNullObj(cancellations[0]).title}</div>
                    <div className='Room-features-additionalInfo'>{!isArrayNull(cancellations) && handleNullObj(cancellations[0]).additionalInfo}</div>
                    <div className='Room-features-descriptions'>
                        {!isArrayNull(features) && features.map( (feature, id) => {
                            return (
                                <div key={id} className='Room-features-description'>{feature.title}</div>
                            )
                        })}
                    </div>
                </div>
                <div className='Room-welcomeRewards'>
                    <div>Hotels.com™ 호텔스닷컴 리워드<br/>적립<br/>사용</div>
                </div>
                <div className='Room-price'>
                    <div className='Room-price-per-day'>{current}</div>
                    <div className='Room-price-info'>{info}</div>
                    <div className='Room-price-total'>{totalPrice[3]} : {totalPrice[1].split(':')[0]}</div>
                </div>
            </div>
        )
    }
    const RoomRatePlans = () => {
        return (
            <>{!isArrayNull(ratePlans) && ratePlans.map( (ratePlan, id) => {
                return (
                    <RatePlan key={id} ratePlan={ratePlan}/>
                )
            })}
            </>
        )
    }
    return ( 
        <div className='Room-container'>
            <div className='Room-summary'>
                <RoomThumbnail/>
                <RoomInfo/>
            </div>
            <div className='Room-plan'>
                <RoomRatePlans/>
            </div>
        </div>
    )
}
export default Room

Room.js 파일을 위와 같이 수정하자!

.Room-container{
    background: #f6f4f3;
    width: 100%;
    margin-top: 20px;

    display: flex;
    justify-content: center;
    align-items: flex-start;
}
.Room-summary{
    width: 250px;
    padding: 15px;
    flex-shrink: 0;
    /* border: 1px solid orange; */
}
.Room-plan{
    flex: 1;
    border: 1px solid lightgray;
    background: white;
    margin-top: 15px;
    margin-bottom: 15px;
    margin-right: 15px;
}
.Room-thumbnail{
    width: 100%;
    overflow: hidden;
}
.Room-thumbnail img{
    width: 100%;
    height: 100%;
    border-radius: 5px;
}
.Room-info{
    margin-top: 15px;
}
.Room-name{
    font-weight: bold;
    font-size: 1.2rem;
}
.Room-max-occupancy{
    margin-top: 10px;
    font-size: 0.9rem;
}
.Room-more-info{
    margin-top: 10px;
    color: #156bc1;
    cursor: pointer;
    font-weight: bold;
    font-size: 0.9rem;
}
.Room-rateplan{
    width: 100%;
    padding: 15px;
    box-sizing: border-box;
    border-bottom: 1px solid lightgray;

    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: flex-start;
}
.Room-features{
    /* border: 1px solid brown; */
    flex: 1;
}
.Room-features-title{
    color: #218242;
    font-size: 0.95rem;
}
.Room-features-additionalInfo{
    font-size: 0.8rem;
}
.Room-features-descriptions{
    margin-top: 10px;
    color: #218242;
    font-size: 0.95rem;
}
.Room-features-description:nth-child(2){
    color: black;
}
.Room-welcomeRewards{
    flex: 1;
    color: #7b1fa2;
    font-size: 0.95rem;
}
.Room-price{
    /* border: 1px solid green; */
    flex: 1;
    text-align: right;
}
.Room-price-per-day{
    color: #333333;
    font-size: 1.2rem;
    font-weight: bold;
}
.Room-price-info{
    color: gray;
    font-size: 0.7rem;
}
.Room-price-total{
    margin-right: 30px;
    font-weight: bold;
    font-size: 0.7rem;
}

.Modal-header{
    padding: 16px 12px;
    color: #d32f2f;
    font-weight: bold;
    font-size: 1.1rem;
    box-sizing: border-box;

    width: 100%;
    height: 50px;
    border-bottom: 1px solid lightgray;

    display: flex;
    justify-content: flex-start;
    align-items: center;

    background: white;
    margin-bottom: auto;
}
.Modal-close{
    width: 30px;
    height: 30px;
    text-align: center;
    line-height: 30px;
    cursor: pointer;
}
.Modal-room-type{
    margin-left: 40px;
    text-align: left;
    flex:1;
}
.Modal-body{
    width: 100%;
    height: 650px;

    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    align-items: center;
    padding: 20px;
    color: var(--grey-1);
    font-size: 0.9rem;
    font-weight: 400;
    box-sizing: border-box;

    overflow-x: none;
    overflow-y: auto;
}
.Modal-thumbnail-container{
    width: 100%;
    display: flex;
    justify-content: flex-start;
    align-items: flex-start;
}
.Modal-thumbnail{
    width: 500px;
    height: 280px;
    overflow: hidden;
}
.Modal-thumbnail img{
    width: 100%;
    height: 100%;
}
.Modal-maxOccupancy{
    flex: 1;
    margin-left: 15px;
    text-align: left;
}
.Modal-room-amenity{
    width: 100%;
    border-top: 1px solid lightgray;
    margin-top: 15px;
    padding-top: 15px;
    padding-bottom: 15px;
    text-align: left;
}
.Modal-room-facility{
    width: 100%;
    border-top: 1px solid lightgray;
    margin-top: 15px;
    padding-top: 15px;
    padding-bottom: 15px;
}
.Modal-room-details-text{
    text-align: left;
    font-weight: bold;
    font-size: 1.2rem;
    margin-bottom: 10px;
}
.Modal-room-details{
    columns: 2 auto;
    text-align: left;
    color: #333333;
    line-height: 25px;
}

Room.css 파일을 위와 같이 수정하자!

 

객실 정보 보기 버튼을 클릭한 화면

 

728x90