Merged in feat/SW-3224-move-bookingcode-filter-to-booking-flow (pull request #2608)

feat(SW-3224): Move bookingcode filter to the booking-flow package

* feat(SW-3224): Moved bookingcode filter to the booking-flow package


Approved-by: Anton Gunnarsson
This commit is contained in:
Hrishikesh Vaipurkar
2025-08-11 12:10:59 +00:00
parent 37c311d826
commit 54e57843d5
8 changed files with 8 additions and 353 deletions

View File

@@ -4,6 +4,7 @@ import { useCallback, useMemo, useRef, useState } from "react"
import { useIntl } from "react-intl"
import { useMediaQuery } from "usehooks-ts"
import BookingCodeFilter from "@scandic-hotels/booking-flow/BookingCodeFilter"
import {
BookingCodeFilterEnum,
useBookingCodeFilterStore,
@@ -27,7 +28,6 @@ import Link from "@/components/TempDesignSystem/Link"
import useLang from "@/hooks/useLang"
import { useScrollToTop } from "@/hooks/useScrollToTop"
import BookingCodeFilter from "../../BookingCodeFilter"
import FilterAndSortModal from "../../Filters/FilterAndSortModal"
import HotelListing from "../HotelListing"
import { getVisibleHotels } from "./utils"

View File

@@ -1,9 +1,9 @@
import BookingCodeFilter from "@scandic-hotels/booking-flow/BookingCodeFilter"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import Subtitle from "@scandic-hotels/design-system/Subtitle"
import { Typography } from "@scandic-hotels/design-system/Typography"
import HotelCardListing from "@/components/HotelReservation/HotelCardListing"
import BookingCodeFilter from "@/components/HotelReservation/SelectHotel/BookingCodeFilter"
import HotelFilter from "@/components/HotelReservation/SelectHotel/Filters/HotelFilter"
import HotelCount from "@/components/HotelReservation/SelectHotel/HotelCount"
import HotelSorter from "@/components/HotelReservation/SelectHotel/HotelSorter"

View File

@@ -1,124 +0,0 @@
.bookingCodeFilter {
display: flex;
justify-content: flex-end;
}
.dialog {
border-radius: var(--Corner-radius-md);
background-color: var(--Surface-Primary-Default);
box-shadow: var(--popup-box-shadow);
max-width: 340px;
}
.radioGroup {
display: grid;
gap: var(--Space-x1);
padding: 0;
}
.radio {
padding: var(--Space-x1);
}
.radio[data-hovered] {
cursor: pointer;
}
.radio[data-focus-visible]::before {
outline: 1px auto var(--Border-Interactive-Focus);
}
.radio {
display: flex;
align-items: center;
}
.radio::before {
flex-shrink: 0;
content: "";
margin-right: var(--Space-x15);
background-color: var(--Surface-UI-Fill-Default);
width: 24px;
height: 24px;
border-radius: 50%;
box-shadow: inset 0 0 0 2px var(--Base-Border-Normal);
}
.radio[data-selected]::before {
box-shadow: inset 0 0 0 8px var(--Surface-UI-Fill-Active);
}
.modalOverlay {
position: fixed;
inset: 0;
background-color: var(--Overlay-40);
&[data-entering] {
animation: overlay-fade 200ms;
}
&[data-exiting] {
animation: overlay-fade 150ms reverse ease-in;
}
}
.modal {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: var(--Space-x2) var(--Space-x05);
border-radius: var(--Corner-radius-md) var(--Corner-radius-md) 0 0;
background-color: var(--Surface-Primary-Default);
box-shadow: 0px 0px 14px 6px rgba(0, 0, 0, 0.1);
&[data-entering] {
animation: modal-anim 200ms;
}
&[data-exiting] {
animation: modal-anim 150ms reverse ease-in;
}
}
.modalDialog {
display: grid;
gap: var(--Space-x2);
padding: 0 var(--Space-x1);
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 var(--Space-x1);
}
@media screen and (min-width: 768px) {
.radioGroup {
padding: var(--Space-x1);
}
.modalOverlay {
display: none;
}
}
@keyframes overlay-fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes modal-anim {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}

View File

@@ -1,225 +0,0 @@
"use client"
import { useEffect, useState } from "react"
import {
Dialog,
DialogTrigger,
Modal,
ModalOverlay,
Popover,
Radio,
RadioGroup,
} from "react-aria-components"
import { useIntl } from "react-intl"
import { useMediaQuery } from "usehooks-ts"
import { BookingCodeFilterEnum } from "@scandic-hotels/booking-flow/stores/bookingCode-filter"
import { ChipButton } from "@scandic-hotels/design-system/ChipButton"
import { IconButton } from "@scandic-hotels/design-system/IconButton"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { trpc } from "@scandic-hotels/trpc/client"
import { RateTypeEnum } from "@scandic-hotels/trpc/enums/rateType"
import { useRatesStore } from "@/stores/select-rate"
import { useRoomContext } from "@/contexts/SelectRate/Room"
import useLang from "@/hooks/useLang"
import styles from "./bookingCodeFilter.module.css"
export default function BookingCodeFilter() {
const intl = useIntl()
const lang = useLang()
const [isOpen, setIsOpen] = useState(false)
const [isDesktop, setIsDesktop] = useState(false)
const displayAsPopover = useMediaQuery("(min-width: 768px)")
const utils = trpc.useUtils()
const {
actions: { appendRegularRates, selectFilter },
bookingRoom,
rooms,
selectedFilter,
selectedPackages,
} = useRoomContext()
const booking = useRatesStore((state) => state.booking)
const bookingCodeFilterItems = [
{
label: intl.formatMessage({
defaultMessage: "Booking code rates",
}),
value: BookingCodeFilterEnum.Discounted,
},
{
label: intl.formatMessage({
defaultMessage: "All rates",
}),
value: BookingCodeFilterEnum.All,
},
]
async function updateFilterValue(selectedFilter: string) {
selectFilter(selectedFilter as BookingCodeFilterEnum)
if (selectedFilter === BookingCodeFilterEnum.All) {
const room = await utils.hotel.availability.selectRate.room.fetch({
booking: {
...booking,
room: {
...bookingRoom,
bookingCode: undefined,
packages: selectedPackages.map((pkg) => pkg.code),
},
},
lang,
})
appendRegularRates(room?.roomConfigurations)
}
}
const hideFilter = rooms.some((room) =>
room.products.some((product) => {
const isRedemption = Array.isArray(product)
if (isRedemption) {
return true
}
switch (product.rateDefinition.rateType) {
case RateTypeEnum.Arb:
case RateTypeEnum.CorporateCheque:
case RateTypeEnum.Voucher:
return true
default:
return false
}
})
)
// To fix the hyderation error
useEffect(() => {
setIsDesktop(displayAsPopover)
}, [displayAsPopover])
if (hideFilter || !booking.bookingCode) {
return null
}
return (
<>
<div className={styles.bookingCodeFilter}>
<DialogTrigger isOpen={isOpen} onOpenChange={setIsOpen}>
<ChipButton variant="Outlined">
{
bookingCodeFilterItems.find(
(item) => item.value === selectedFilter
)?.label
}
<MaterialIcon
icon="keyboard_arrow_down"
size={20}
color="CurrentColor"
/>
</ChipButton>
{isDesktop ? (
<Popover placement="bottom end" isNonModal>
<Dialog className={styles.dialog}>
{({ close }) => {
function handleChangeFilterValue(value: string) {
updateFilterValue(value)
close()
}
return (
<Typography variant="Body/Paragraph/mdRegular">
<RadioGroup
aria-label={intl.formatMessage({
defaultMessage: "Booking Code Filter",
})}
onChange={handleChangeFilterValue}
name="bookingCodeFilter"
value={selectedFilter}
className={styles.radioGroup}
>
{bookingCodeFilterItems.map((item) => (
<Radio
aria-label={item.label}
key={item.value}
value={item.value}
className={styles.radio}
autoFocus={selectedFilter === item.value}
>
{item.label}
</Radio>
))}
</RadioGroup>
</Typography>
)
}}
</Dialog>
</Popover>
) : (
<ModalOverlay className={styles.modalOverlay} isDismissable>
<Modal className={styles.modal}>
<Dialog className={styles.modalDialog}>
{({ close }) => {
function handleChangeFilterValue(value: string) {
updateFilterValue(value)
close()
}
return (
<>
<div className={styles.header}>
<Typography variant="Title/Subtitle/md">
<h3>
{intl.formatMessage({
defaultMessage: "Room rates",
})}
</h3>
</Typography>
<IconButton
theme="Black"
style="Muted"
onPress={() => {
close()
}}
>
<MaterialIcon
icon="close"
size={24}
color="CurrentColor"
/>
</IconButton>
</div>
<Typography variant="Body/Paragraph/mdRegular">
<RadioGroup
aria-label={intl.formatMessage({
defaultMessage: "Booking Code Filter",
})}
onChange={handleChangeFilterValue}
name="bookingCodeFilter"
value={selectedFilter}
className={styles.radioGroup}
>
{bookingCodeFilterItems.map((item) => (
<Radio
aria-label={item.label}
key={item.value}
value={item.value}
className={styles.radio}
>
{item.label}
</Radio>
))}
</RadioGroup>
</Typography>
</>
)
}}
</Dialog>
</Modal>
</ModalOverlay>
)}
</DialogTrigger>
</div>
</>
)
}

View File

@@ -56,7 +56,6 @@ export default function RoomsHeader() {
<div className={styles.filters}>
<RemoveBookingCodeButton />
<RoomPackageFilter />
{/* <BookingCodeFilter /> */}
</div>
</div>
)

View File

@@ -13,12 +13,16 @@ import {
import { useIntl } from "react-intl"
import { useMediaQuery } from "usehooks-ts"
import { BookingCodeFilterEnum,useBookingCodeFilterStore } from "@scandic-hotels/booking-flow/stores/bookingCode-filter"
import { ChipButton } from "@scandic-hotels/design-system/ChipButton"
import { IconButton } from "@scandic-hotels/design-system/IconButton"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import {
BookingCodeFilterEnum,
useBookingCodeFilterStore,
} from "../../stores/bookingCode-filter"
import styles from "./bookingCodeFilter.module.css"
export default function BookingCodeFilter() {

View File

@@ -11,6 +11,7 @@
"test:watch": "vitest"
},
"exports": {
"./BookingCodeFilter": "./lib/components/BookingCodeFilter/index.tsx",
"./BookingWidget": "./lib/components/BookingWidget/index.tsx",
"./BookingWidget/FloatingBookingWidget": "./lib/components/BookingWidget/FloatingBookingWidget/index.tsx",
"./BookingWidget/Skeleton": "./lib/components/BookingWidget/Skeleton.tsx",