iT邦幫忙

2022 iThome 鐵人賽

DAY 24
2
Modern Web

自己做一個價值幾十萬的動態網站,學會Mern開發、前台UI設計各式觀念與各式Lib、typescript你該學會的前端技術系列 第 24

「全端挑戰」useLocation.pathname應用,optionsContext資料同步更新、空房情況UI設計與串接room顯示資料

  • 分享至 

  • xImage
  •  

鐵人賽 Day24自己做一個價值幾十萬的動態網站

第二十四課:resveration 將optionsContext條件行為計算後,同步更新到各個需要的component內

前一天我們完成了相關的SearchItem搜尋欄,並讓真實資料得以被filter今天將來把剩下的hotelPage做結尾,包括完成room的實際訂房UI與資料等連動前置作業。

將真實飯店資料連動到hotelPage,useLocation的再次應用

這邊我們來示範一般產品類別如何跳轉到該產品詳細頁面,一樣我們會利用到useLocation,而第一次使用useLocation是在homePage與hotelsListPage的搜尋連接上,利用到了useNavgate與useLocation.state的配合,而這次我們要來使用useLocation的其他項目


<Link to={`/hotels/${dataDetail._id}`}>

了解link可以這樣做後,最前面的homePage的熱門景點如果也想要直接點擊,就跳出該熱門飯店的詳細資料就可以這樣做。
並我們將使用useLocation.pathname來抓取我們傳在分頁url的hotelid

並抓取到hotelid後,我們要用它來繼續fetchdata,所以一樣使用到我們的useFetch加上我們的getHotel method Api,

const locationHotelUrl = useLocation()
const hotelid = locationHotelUrl.pathname.split("/")[2]
const { data, loading, error } = useFetch(`/hotels/find/${hotelid}`)
console.log(data) //可以來檢查一下是否抓到正確的資料

上述成功後,useFetch應該也會成功抓取到data,並我們就可以使用data來把我們的資料都替換掉。




將資料成功換上後
hotel Page div

製作空房情況UI設計與串接room顯示資料


接下來的目標,我們要將他製作空房情況,並先講room使用useFetch測試看能不能成功抓取我們該飯店的所有房型,但還未加入該時段確定有房間的情況,所以第一步我們也一樣先來完成UI設計,首先先製作並跳轉去這個空房情況,將把這個空房情況命名為reservation

const {user} =useContext(LoginContext)
const [openReservation, setOpenReservation] = useState(false);
const navgator = useNavigate()
const handleReservation = () => {
if (user) {
  setOpenReservation(true)
} else {
  navgator("/login")
}
}


並這個空房情況彈跳視窗到時候,不會歸類在哪一個div裡面就是直接顯示全螢幕,所以將他放在footer下面

<div className='Reservation'>
        <div className="container">
        <div className="wrapper">
            <div className="title">
                <h2>空房情況</h2>
                <h3>幾號幾號幾晚 大人小孩 </h3>
                <FontAwesomeIcon icon={faCircleXmark}  />
            </div>
            <div className="body">
                <div className="roomTitle">
                    <div>客房類型</div>
                    <div>適合人數</div>
                    <div>房型今日價格</div>
                    <div>選擇房型編號</div>
                </div>
                <div className='roomData'>
                    <div className='roomColumn'>
                       room資料到時候存放地點
                    </div>
                    <button className='reservationbtn'> 現在預訂</button>
                </div>
            </div >
        </div>
    </div>
</div >

reservation.scss連結,因篇幅關係這邊scss就先不花時間在講解。
大概styling後,我們要先來控制他的開關與讓Room資料可以被導入,所以要做到這兩件事,我們必須把控制開關的useState導入,並導入hotelid才能用這個id去把所有的hotel's rooms抓吃出來而用到的Api method是我們之前寫的getHotelRooms.

<Reservation openSetting={setOpenReservation} hotelid={hotelid} />


完成這邊後,大致就能展現出我們hotel與相關room的所有資料,

<div className='roomColumn'>
{loading && <>載入中</>}
{data.map((room, i) =>
(
<div className="roomInfo" key={i}>
     <div >
        {room.title}<br/><p>{room.desc}</p>
    </div>
    <div >{room.maxPeople}</div>
    <div >TWD {room.price}</div>
    <div >
        {room.roomNumbers?.map((item, i) => (
            <span key={i}>
                <input type="checkbox" value={item._id} />
                {item.number}<br/>
            </span>
        ))}
    </div>
    </div>)
)}
</div>

上述的資料型態可以邊打邊與我們之前一開始所設置的room Model去做對照,並接下來在確定送出預定資料前,我們要先來補之前的缺,將我們的optionsContext做各個分頁的資料串連。

將之前所有的option操作行為進行串接,顯示訂房時間與相關人數條件

這邊將來處理optionsContext中最重要的dates並同時都串接到我們searchItem、hotelPage到我們的現在新的空房情況,來顯示這些訂房目前的條件選擇。

首先先來完成我們的hotelsList中的searchItem,讓他同時顯示,一共幾晚並會這樣得價格是多少。這邊會有些細節處理,如沒有選擇日期則先跳出飯店的推薦就不顯示價格,因為無法計算的細節或是針對這一開始的日期選擇,就只跳出時間上可以的飯店(目前我們是先以預訂時如果不行我們會把可以勾選的checkBox給取消,讓他不能預訂)但因為我們資料庫資料太少與篇幅關係,將先以如何計算與串接為主。

<SearchItem active={index==0 && "active"} key={item._id} dataDetail={item}   conditions={options} dates={date} />



所以這邊我們會發現getTime會讓我們回傳的datesLength都是呈現毫秒的狀態,但我們想要的是顯示幾晚,所以我們可以直接讓他除以一天的毫秒數也就是86400*1000

export const ReservationDatesAndPrice = (startDate, endDate, hotelsPrice, roomsPrice)=>{
    const MSecond_per_day=1000*86400;
    const DatesLength = (Math.abs(endDate?.getTime()-startDate?.getTime())||0 )/MSecond_per_day
    const totalHotelsPrice = DatesLength*hotelsPrice||0
    const totalRoomsPrice = DatesLength*roomsPrice||0
    return{DatesLength,totalHotelsPrice,totalRoomsPrice}
}

所以回到searchItem那邊把我們函數導入並使用

const hotelsPrice = dataDetail.cheapestPrice
const { DatesLength, totalHotelsPrice } = ReservationDatesAndPrice(dates[0]?.startDate, dates[0]?.endDate, hotelsPrice)

好了以後就可以替換成我們要的資訊,並特別處理一下0晚的情況,
所以在我們的detailRight中的optionDes來新增我們的條件,

<span className="optionDes">
  {DatesLength== 0?<>請先選擇住宿日期</> : `總共 ${DatesLength} 晚`}
    <br/>{conditions.adult} 位大人 {conditions.children != 0 && `、${conditions.children} 位小孩`}
  </span>
  <span className="price">
    {DatesLength== 0 ? `TWD ${dataDetail.cheapestPrice} 價格`:`TWD ${totalHotelsPrice} 價格`}
  </span>

並利用這個方式也來快速處理我們的hotel Page與顯示在我們的Reservaiton最終空房情況的預訂上。


hotel Page內容

const { city, date, options,dispatch } = useContext(OptionsContext)
const hotelsPrice = data.cheapestPrice
const { DatesLength, totalHotelsPrice } = ReservationDatesAndPrice(date[0]?.startDate, date[0]?.endDate, hotelsPrice)
<div className="hotelDesPrice">
  <h2>住宿特色 </h2>
  <h3> {format(date[0]?.startDate, "MM/dd/yyyy")} - {format(date[0]?.endDate, "MM/dd/yyyy")}</h3>
  <p>入住 {DatesLength} 晚的最佳選擇!
    此住宿位於台南評分最高的地區,地理位置評分高達 {data.rating} 分
    深受獨行旅客歡迎</p>
  <h2>TWD {totalHotelsPrice}</h2>
  <button onClick={handleReservation} >現在就預訂</button>
</div>

並最後的Reservation Component,快速完成,這邊DatesLength可以選擇要在Reservation在計算一次還是直接用props從我們的hotelPage傳入到Reservation Component之中,而我選擇後者,畢竟不想在計算重複的東西一次。



最後附上day24的完整版
github Day24完成的連結

結論

這邊其實已經快進入尾聲,後續都是熟能生巧的一些小功能補上,所以想在day24-25內趕快完成,篇幅上略有刪減但還是有些小多,這邊可以練習是站在使用者使用的角度去設想,不管在哪一個行業以全端或是自己創業者的角度,要如何與工程師溝通有概念,其實在完成時就會發現光是看似簡單的訂房卻包含著很多小巧思跟細節,本作者雖然是第一次開發訂房的專案,這次卻有學到很多,而這些經驗很難用口述傳達,反而會是自己在越來越深入時,覺得自己還有很多細節要去完成跟精進,如這個專案順利結案,預計下一個大專案會是想要做台灣本土Dcard的致敬,並到時候如果真的有做,未來我們大家在YT上見,並讓我先去學個剪接。


上一篇
「全端挑戰」搜尋價格區間Api、前後端的query應用、useFetch與useEffect的配合
下一篇
「全端挑戰」Mui與framerMotion特效介紹,創建新model,Order訂房下單Api與CheckBox函數紀錄表單useState
系列文
自己做一個價值幾十萬的動態網站,學會Mern開發、前台UI設計各式觀念與各式Lib、typescript你該學會的前端技術30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言