feat(SW-650): fix sticky bug on booking widget mob

This commit is contained in:
Niclas Edenvin
2024-10-23 20:49:08 +02:00
committed by Erik Tiekstra
parent 20e3c9a35f
commit 63dbbac014
4 changed files with 102 additions and 76 deletions

View File

@@ -146,11 +146,10 @@ export default function BookingWidgetClient({
return ( return (
<FormProvider {...methods}> <FormProvider {...methods}>
<section <section ref={bookingWidgetRef} className={styles.containerDesktop}>
ref={bookingWidgetRef} <Form locations={locations} type={type} />
className={styles.container} </section>
data-open={isOpen} <section className={styles.containerMobile} data-open={isOpen}>
>
<button <button
className={styles.close} className={styles.close}
onClick={closeMobileSearch} onClick={closeMobileSearch}

View File

@@ -1,15 +1,17 @@
"use client" "use client"
import { useEffect, useState } from "react" import { useEffect, useMemo, useRef, useState } from "react"
import { useWatch } from "react-hook-form" import { useWatch } from "react-hook-form"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { dt } from "@/lib/dt" import { dt } from "@/lib/dt"
import { StickyElementNameEnum } from "@/stores/sticky-position"
import { EditIcon, SearchIcon } from "@/components/Icons" import { EditIcon, SearchIcon } from "@/components/Icons"
import Divider from "@/components/TempDesignSystem/Divider" import Divider from "@/components/TempDesignSystem/Divider"
import Body from "@/components/TempDesignSystem/Text/Body" import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption" import Caption from "@/components/TempDesignSystem/Text/Caption"
import useLang from "@/hooks/useLang" import useLang from "@/hooks/useLang"
import useStickyPosition from "@/hooks/useStickyPosition"
import styles from "./button.module.css" import styles from "./button.module.css"
@@ -29,6 +31,12 @@ export default function MobileToggleButton({
const location = useWatch({ name: "location" }) const location = useWatch({ name: "location" })
const rooms: BookingWidgetSchema["rooms"] = useWatch({ name: "rooms" }) const rooms: BookingWidgetSchema["rooms"] = useWatch({ name: "rooms" })
const bookingWidgetMobileRef = useRef(null)
useStickyPosition({
ref: bookingWidgetMobileRef,
name: StickyElementNameEnum.BOOKING_WIDGET_MOBILE,
})
const parsedLocation: Location | null = location const parsedLocation: Location | null = location
? JSON.parse(decodeURIComponent(location)) ? JSON.parse(decodeURIComponent(location))
: null : null
@@ -42,11 +50,15 @@ export default function MobileToggleButton({
setHasMounted(true) setHasMounted(true)
}, []) }, [])
const locationAndDateIsSet = useMemo(
() => parsedLocation && d,
[parsedLocation, d]
)
if (!hasMounted) { if (!hasMounted) {
return null return null
} }
if (parsedLocation && d) {
const totalRooms = rooms.length const totalRooms = rooms.length
const totalAdults = rooms.reduce((acc, room) => { const totalAdults = rooms.reduce((acc, room) => {
if (room.adults) { if (room.adults) {
@@ -60,35 +72,20 @@ export default function MobileToggleButton({
} }
return acc return acc
}, 0) }, 0)
return (
<div className={styles.complete} onClick={openMobileSearch} role="button">
<div>
<Caption color="red">{parsedLocation.name}</Caption>
<Caption>
{`${selectedFromDate} - ${selectedToDate} (${intl.formatMessage(
{ id: "booking.nights" },
{ totalNights: nights }
)}) ${intl.formatMessage({ id: "booking.adults" }, { totalAdults })}, ${
totalChildren > 0
? intl.formatMessage(
{ id: "booking.children" },
{ totalChildren }
) + ", "
: ""
}${intl.formatMessage({ id: "booking.rooms" }, { totalRooms })}`}
</Caption>
</div>
<div className={styles.icon}>
<EditIcon color="white" />
</div>
</div>
)
}
return ( return (
<div className={styles.partial} onClick={openMobileSearch} role="button"> <div
className={locationAndDateIsSet ? styles.complete : styles.partial}
onClick={openMobileSearch}
role="button"
ref={bookingWidgetMobileRef}
>
{!locationAndDateIsSet && (
<>
<div> <div>
<Caption color="red">{intl.formatMessage({ id: "Where to" })}</Caption> <Caption color="red">
{intl.formatMessage({ id: "Where to" })}
</Caption>
<Body color="uiTextPlaceholder"> <Body color="uiTextPlaceholder">
{parsedLocation {parsedLocation
? parsedLocation.name ? parsedLocation.name
@@ -110,6 +107,32 @@ export default function MobileToggleButton({
<div className={styles.icon}> <div className={styles.icon}>
<SearchIcon color="white" /> <SearchIcon color="white" />
</div> </div>
</>
)}
{locationAndDateIsSet && (
<>
<div>
<Caption color="red">{parsedLocation?.name}</Caption>
<Caption>
{`${selectedFromDate} - ${selectedToDate} (${intl.formatMessage(
{ id: "booking.nights" },
{ totalNights: nights }
)}) ${intl.formatMessage({ id: "booking.adults" }, { totalAdults })}, ${
totalChildren > 0
? intl.formatMessage(
{ id: "booking.children" },
{ totalChildren }
) + ", "
: ""
}${intl.formatMessage({ id: "booking.rooms" }, { totalRooms })}`}
</Caption>
</div>
<div className={styles.icon}>
<EditIcon color="white" />
</div>
</>
)}
</div> </div>
) )
} }

View File

@@ -1,5 +1,11 @@
.containerDesktop,
.containerMobile,
.close {
display: none;
}
@media screen and (max-width: 767px) { @media screen and (max-width: 767px) {
.container { .containerMobile {
background-color: var(--UI-Input-Controls-Surface-Normal); background-color: var(--UI-Input-Controls-Surface-Normal);
bottom: -100%; bottom: -100%;
display: grid; display: grid;
@@ -14,7 +20,7 @@
border-radius: var(--Corner-radius-Large) var(--Corner-radius-Large) 0 0; border-radius: var(--Corner-radius-Large) var(--Corner-radius-Large) 0 0;
} }
.container[data-open="true"] { .containerMobile[data-open="true"] {
bottom: 0; bottom: 0;
} }
@@ -25,7 +31,7 @@
justify-self: flex-end; justify-self: flex-end;
} }
.container[data-open="true"] + .backdrop { .containerMobile[data-open="true"] + .backdrop {
background-color: rgba(0, 0, 0, 0.4); background-color: rgba(0, 0, 0, 0.4);
height: 100%; height: 100%;
left: 0; left: 0;
@@ -37,7 +43,7 @@
} }
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
.container { .containerDesktop {
display: block; display: block;
box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.05); box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.05);
position: sticky; position: sticky;
@@ -45,10 +51,6 @@
z-index: 10; z-index: 10;
background-color: var(--Base-Surface-Primary-light-Normal); background-color: var(--Base-Surface-Primary-light-Normal);
} }
.close {
display: none;
}
} }
@media screen and (min-width: 1367px) { @media screen and (min-width: 1367px) {

View File

@@ -3,6 +3,7 @@ import { create } from "zustand"
export enum StickyElementNameEnum { export enum StickyElementNameEnum {
SITEWIDE_ALERT = "SITEWIDE_ALERT", SITEWIDE_ALERT = "SITEWIDE_ALERT",
BOOKING_WIDGET = "BOOKING_WIDGET", BOOKING_WIDGET = "BOOKING_WIDGET",
BOOKING_WIDGET_MOBILE = "BOOKING_WIDGET_MOBILE",
HOTEL_TAB_NAVIGATION = "HOTEL_TAB_NAVIGATION", HOTEL_TAB_NAVIGATION = "HOTEL_TAB_NAVIGATION",
HOTEL_STATIC_MAP = "HOTEL_STATIC_MAP", HOTEL_STATIC_MAP = "HOTEL_STATIC_MAP",
} }
@@ -31,6 +32,7 @@ interface StickyStore {
const priorityMap: Record<StickyElementNameEnum, number> = { const priorityMap: Record<StickyElementNameEnum, number> = {
[StickyElementNameEnum.SITEWIDE_ALERT]: 1, [StickyElementNameEnum.SITEWIDE_ALERT]: 1,
[StickyElementNameEnum.BOOKING_WIDGET]: 2, [StickyElementNameEnum.BOOKING_WIDGET]: 2,
[StickyElementNameEnum.BOOKING_WIDGET_MOBILE]: 2,
[StickyElementNameEnum.HOTEL_TAB_NAVIGATION]: 3, [StickyElementNameEnum.HOTEL_TAB_NAVIGATION]: 3,
[StickyElementNameEnum.HOTEL_STATIC_MAP]: 3, [StickyElementNameEnum.HOTEL_STATIC_MAP]: 3,