feat: break apart loading of room availability and hotel card
feat: add skeletons
This commit is contained in:
@@ -4,9 +4,9 @@ import { Suspense } from "react"
|
||||
import { dt } from "@/lib/dt"
|
||||
import { getHotelData, getLocations } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import LoadingSpinner from "@/components/Current/LoadingSpinner"
|
||||
import HotelInfoCard from "@/components/HotelReservation/SelectRate/HotelInfoCard"
|
||||
import { RoomsContainer } from "@/components/HotelReservation/SelectRate/Rooms/RoomsContainer"
|
||||
import { RoomsContainerSkeleton } from "@/components/HotelReservation/SelectRate/Rooms/RoomsContainerSkeleton"
|
||||
import { getHotelReservationQueryParams } from "@/components/HotelReservation/SelectRate/RoomSelection/utils"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
import { safeTry } from "@/utils/safeTry"
|
||||
@@ -71,7 +71,8 @@ export default async function SelectRatePage({
|
||||
adultCount={adults}
|
||||
childArray={children ?? []}
|
||||
/>
|
||||
<Suspense key={hotelId} fallback={<LoadingSpinner />}>
|
||||
|
||||
<Suspense key={hotelId} fallback={<RoomsContainerSkeleton />}>
|
||||
<RoomsContainer
|
||||
hotelId={hotelId}
|
||||
lang={params.lang}
|
||||
|
||||
@@ -42,23 +42,10 @@ export default async function HotelInfoCard({
|
||||
const hotelAttributes = hotelData?.data.attributes
|
||||
const intl = await getIntl()
|
||||
|
||||
// const noRoomsAvailable = useRoomAvailableStore(
|
||||
// (state) => state.noRoomsAvailable
|
||||
// )
|
||||
// const setNoRoomsAvailable = useRoomAvailableStore(
|
||||
// (state) => state.setNoRoomsAvailable
|
||||
// )
|
||||
|
||||
const sortedFacilities = hotelAttributes?.detailedFacilities
|
||||
.sort((a, b) => b.sortOrder - a.sortOrder)
|
||||
.slice(0, 5)
|
||||
|
||||
// useEffect(() => {
|
||||
// if (noAvailability) {
|
||||
// setNoRoomsAvailable()
|
||||
// }
|
||||
// }, [noAvailability, setNoRoomsAvailable])
|
||||
|
||||
return (
|
||||
<article className={styles.container}>
|
||||
{hotelAttributes && (
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
.card {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #fff;
|
||||
border-radius: var(--Corner-radius-Large);
|
||||
border: 1px solid var(--Base-Border-Subtle);
|
||||
position: relative;
|
||||
height: 100%;
|
||||
justify-content: space-between;
|
||||
min-height: 200px;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.imageContainer {
|
||||
aspect-ratio: 16/9;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.priceVariants {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x1);
|
||||
padding: var(--Spacing-x2);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import SkeletonShimmer from "@/components/SkeletonShimmer"
|
||||
|
||||
import styles from "./RoomCardSkeleton.module.css"
|
||||
|
||||
export function RoomCardSkeleton() {
|
||||
return (
|
||||
<article className={styles.card}>
|
||||
{/* image container */}
|
||||
<div className={styles.imageContainer}>
|
||||
<SkeletonShimmer width={"100%"} height="100%" />
|
||||
</div>
|
||||
|
||||
<div className={styles.priceVariants}>
|
||||
{/* price variants */}
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
<SkeletonShimmer key={index} height={"100px"} />
|
||||
))}
|
||||
</div>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
.container {
|
||||
padding: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.filterContainer {
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.skeletonContainer {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
/* used to hide overflowing rows */
|
||||
grid-template-rows: auto;
|
||||
grid-auto-rows: 0;
|
||||
overflow: hidden;
|
||||
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
gap: var(--Spacing-x2);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import { RoomCardSkeleton } from "../RoomSelection/RoomCard/RoomCardSkeleton"
|
||||
|
||||
import styles from "./RoomsContainerSkeleton.module.css"
|
||||
|
||||
type Props = {
|
||||
count?: number
|
||||
}
|
||||
|
||||
export async function RoomsContainerSkeleton({ count = 4 }: Props) {
|
||||
const intl = await getIntl()
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.filterContainer}></div>
|
||||
<div className={styles.skeletonContainer}>
|
||||
{Array.from({ length: count }).map((_, index) => (
|
||||
<RoomCardSkeleton key={index} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -82,6 +82,8 @@ export function getSiteConfigConnections(refs: GetSiteConfigRefData) {
|
||||
const siteConfigData = refs.all_site_config.items[0]
|
||||
const connections: System["system"][] = []
|
||||
|
||||
if (!siteConfigData) return connections
|
||||
|
||||
const alertConnection = siteConfigData.sitewide_alert.alertConnection
|
||||
|
||||
alertConnection.edges.forEach(({ node }) => {
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { create } from "zustand"
|
||||
|
||||
interface RoomAvailabilityState {
|
||||
noRoomsAvailable: boolean
|
||||
setNoRoomsAvailable: () => void
|
||||
setRoomsAvailable: () => void
|
||||
}
|
||||
|
||||
const useRoomAvailableStore = create<RoomAvailabilityState>((set) => ({
|
||||
noRoomsAvailable: false,
|
||||
setNoRoomsAvailable: () => set(() => ({ noRoomsAvailable: true })),
|
||||
setRoomsAvailable: () => set(() => ({ noRoomsAvailable: false })),
|
||||
}))
|
||||
|
||||
export default useRoomAvailableStore
|
||||
Reference in New Issue
Block a user