feat: SW-601 Implement filters and sort in map view
This commit is contained in:
@@ -12,7 +12,7 @@ import {
|
||||
import { MapModal } from "@/components/MapModal"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import { fetchAvailableHotels } from "../../utils"
|
||||
import { fetchAvailableHotels, getFiltersFromHotels } from "../../utils"
|
||||
|
||||
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
@@ -57,6 +57,7 @@ export default async function SelectHotelMapPage({
|
||||
})
|
||||
|
||||
const hotelPins = getHotelPins(hotels)
|
||||
const filterList = getFiltersFromHotels(hotels)
|
||||
|
||||
return (
|
||||
<MapModal>
|
||||
@@ -65,6 +66,7 @@ export default async function SelectHotelMapPage({
|
||||
hotelPins={hotelPins}
|
||||
mapId={googleMapId}
|
||||
hotels={hotels}
|
||||
filterList={filterList}
|
||||
/>
|
||||
</MapModal>
|
||||
)
|
||||
|
||||
@@ -81,6 +81,10 @@
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.close {
|
||||
background: none;
|
||||
border: none;
|
||||
@@ -97,3 +101,69 @@
|
||||
flex: 0 0 auto;
|
||||
border-top: 1px solid var(--Base-Border-Subtle);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.modal {
|
||||
left: 50%;
|
||||
bottom: 50%;
|
||||
height: min(80dvh, 680px);
|
||||
width: min(80dvw, 960px);
|
||||
translate: -50% 50%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
padding: var(--Spacing-x2) var(--Spacing-x3);
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--Base-Border-Subtle);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: var(--Base-Surface-Primary-light-Normal);
|
||||
z-index: 1;
|
||||
border-top-left-radius: var(--Corner-radius-large);
|
||||
border-top-right-radius: var(--Corner-radius-large);
|
||||
}
|
||||
|
||||
.title {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.content {
|
||||
gap: var(--Spacing-x4);
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.filters {
|
||||
overflow-y: unset;
|
||||
}
|
||||
|
||||
.sorter,
|
||||
.filters,
|
||||
.footer,
|
||||
.divider {
|
||||
padding: 0 var(--Spacing-x3);
|
||||
}
|
||||
|
||||
.footer {
|
||||
flex-direction: row-reverse;
|
||||
justify-content: space-between;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
background: var(--Base-Surface-Primary-light-Normal);
|
||||
z-index: 1;
|
||||
border-bottom-left-radius: var(--Corner-radius-large);
|
||||
border-bottom-right-radius: var(--Corner-radius-large);
|
||||
padding: var(--Spacing-x2) var(--Spacing-x3);
|
||||
}
|
||||
|
||||
.filters aside h1 {
|
||||
margin-bottom: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.filters aside > div:last-child {
|
||||
margin-top: var(--Spacing-x4);
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import { useHotelFilterStore } from "@/stores/hotel-filters"
|
||||
|
||||
import { CloseLargeIcon, FilterIcon } from "@/components/Icons"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
|
||||
import HotelFilter from "../HotelFilter"
|
||||
import HotelSorter from "../HotelSorter"
|
||||
@@ -47,12 +49,20 @@ export default function FilterAndSortModal({
|
||||
>
|
||||
<CloseLargeIcon />
|
||||
</button>
|
||||
<Subtitle
|
||||
type="two"
|
||||
textAlign="center"
|
||||
className={styles.title}
|
||||
>
|
||||
{intl.formatMessage({ id: "Filter and sort" })}
|
||||
</Subtitle>
|
||||
</header>
|
||||
<div className={styles.sorter}>
|
||||
<HotelSorter />
|
||||
</div>
|
||||
<Divider color="subtle" className="divider" />
|
||||
<div className={styles.filters}>
|
||||
<HotelFilter filters={filters} />
|
||||
<HotelFilter filters={filters} type="modal" />
|
||||
</div>
|
||||
<footer className={styles.footer}>
|
||||
<Button
|
||||
|
||||
@@ -38,3 +38,17 @@
|
||||
height: 1.25rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.facilities ul.modal {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto auto;
|
||||
margin-top: var(--Spacing-x3);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) and (max-width: 1023) {
|
||||
.facilities ul.modal {
|
||||
grid-template-columns: auto auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@ import styles from "./hotelFilter.module.css"
|
||||
|
||||
import type { HotelFiltersProps } from "@/types/components/hotelReservation/selectHotel/hotelFilters"
|
||||
|
||||
export default function HotelFilter({ className, filters }: HotelFiltersProps) {
|
||||
export default function HotelFilter({
|
||||
className,
|
||||
filters,
|
||||
type,
|
||||
}: HotelFiltersProps) {
|
||||
const intl = useIntl()
|
||||
const searchParams = useSearchParams()
|
||||
const pathname = usePathname()
|
||||
@@ -63,7 +67,7 @@ export default function HotelFilter({ className, filters }: HotelFiltersProps) {
|
||||
<Title as="h4">{intl.formatMessage({ id: "Filter by" })}</Title>
|
||||
<div className={styles.facilities}>
|
||||
<Subtitle>{intl.formatMessage({ id: "Hotel facilities" })}</Subtitle>
|
||||
<ul>
|
||||
<ul className={type ? styles.modal : ""}>
|
||||
{filters.facilityFilters.map((filter) => (
|
||||
<li key={`li-${filter.id}`} className={styles.filter}>
|
||||
<FilterCheckbox
|
||||
@@ -81,7 +85,7 @@ export default function HotelFilter({ className, filters }: HotelFiltersProps) {
|
||||
|
||||
<div className={styles.facilities}>
|
||||
<Subtitle>{intl.formatMessage({ id: "Hotel surroundings" })}</Subtitle>
|
||||
<ul>
|
||||
<ul className={type ? styles.modal : ""}>
|
||||
{filters.surroundingsFilters.map((filter) => (
|
||||
<li key={`li-${filter.id}`} className={styles.filter}>
|
||||
<FilterCheckbox
|
||||
|
||||
@@ -13,6 +13,7 @@ import { BackToTopButton } from "@/components/TempDesignSystem/BackToTopButton"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import FilterAndSortModal from "../FilterAndSortModal"
|
||||
import HotelListing from "./HotelListing"
|
||||
import { getCentralCoordinates } from "./utils"
|
||||
|
||||
@@ -25,6 +26,7 @@ export default function SelectHotelMap({
|
||||
hotelPins,
|
||||
mapId,
|
||||
hotels,
|
||||
filterList,
|
||||
}: SelectHotelMapProps) {
|
||||
const searchParams = useSearchParams()
|
||||
const router = useRouter()
|
||||
@@ -102,8 +104,7 @@ export default function SelectHotelMap({
|
||||
>
|
||||
<CloseLargeIcon />
|
||||
</Button>
|
||||
<span>Filter and sort</span>
|
||||
{/* TODO: Add filter and sort button */}
|
||||
<FilterAndSortModal filters={filterList} />
|
||||
</div>
|
||||
<HotelListing
|
||||
hotels={hotels}
|
||||
|
||||
@@ -41,4 +41,9 @@
|
||||
.container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.filterContainer {
|
||||
justify-content: flex-end;
|
||||
padding: 0 0 var(--Spacing-x1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export type CategorizedFilters = {
|
||||
export type HotelFiltersProps = {
|
||||
filters: CategorizedFilters
|
||||
className?: string
|
||||
type?: "modal"
|
||||
}
|
||||
|
||||
export type Filter = {
|
||||
@@ -16,3 +17,7 @@ export type Filter = {
|
||||
sortOrder: number
|
||||
filter?: string
|
||||
}
|
||||
|
||||
export type HotelFilterModalProps = {
|
||||
filters: CategorizedFilters
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from "@/server/routers/hotels/schemas/image"
|
||||
|
||||
import { HotelData } from "./hotelCardListingProps"
|
||||
import { Filter } from "./hotelFilters"
|
||||
import { CategorizedFilters, Filter } from "./hotelFilters"
|
||||
|
||||
import type { Coordinates } from "@/types/components/maps/coordinates"
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface SelectHotelMapProps {
|
||||
hotelPins: HotelPin[]
|
||||
mapId: string
|
||||
hotels: HotelData[]
|
||||
filterList: CategorizedFilters
|
||||
}
|
||||
|
||||
type ImageSizes = z.infer<typeof imageSizesSchema>
|
||||
|
||||
Reference in New Issue
Block a user