ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 호텔 검색 앱 7 - 호텔 객실 상세정보 보기 구현하기
    프로젝트/호텔 검색 앱 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
Designed by Tistory.