Merged in feat/BOOK-434-users-should-redirect-to- (pull request #3154)

* feat(BOOK-434): Moved redirect to middleware layer
* feat(BOOK-434): Updated to handle no filters available scenario

Approved-by: Erik Tiekstra
This commit is contained in:
Hrishikesh Vaipurkar
2025-11-14 09:51:44 +00:00
parent 3d121be74a
commit f23652b929
7 changed files with 85 additions and 24 deletions

View File

@@ -1,4 +1,4 @@
import { notFound, redirect } from "next/navigation" import { notFound } from "next/navigation"
import { Suspense } from "react" import { Suspense } from "react"
import { import {
@@ -69,11 +69,6 @@ export default async function DestinationCityPage({
const activeSeoFilter = getActiveSeoFilter(seo_filters, filterFromUrl) const activeSeoFilter = getActiveSeoFilter(seo_filters, filterFromUrl)
if (filterFromUrl && !activeSeoFilter) {
const updatedPathname = pathname.replace(`/${filterFromUrl}`, "")
return redirect(`${updatedPathname}${isMapView ? "?view=map" : ""}`)
}
const allHotels = await getHotelsByCityIdentifier(cityIdentifier) const allHotels = await getHotelsByCityIdentifier(cityIdentifier)
const hotelFilters = getFiltersFromHotels(allHotels, lang) const hotelFilters = getFiltersFromHotels(allHotels, lang)

View File

@@ -1,4 +1,4 @@
import { notFound, redirect } from "next/navigation" import { notFound } from "next/navigation"
import { Suspense } from "react" import { Suspense } from "react"
import { import {
@@ -70,11 +70,6 @@ export default async function DestinationCountryPage({
const activeSeoFilter = getActiveSeoFilter(seo_filters, filterFromUrl) const activeSeoFilter = getActiveSeoFilter(seo_filters, filterFromUrl)
if (filterFromUrl && !activeSeoFilter) {
const updatedPathname = pathname.replace(`/${filterFromUrl}`, "")
return redirect(`${updatedPathname}${isMapView ? "?view=map" : ""}`)
}
const [allHotels, allCities] = await Promise.all([ const [allHotels, allCities] = await Promise.all([
getHotelsByCountry(destination_settings.country), getHotelsByCountry(destination_settings.country),
getDestinationCityPagesByCountry(destination_settings.country), getDestinationCityPagesByCountry(destination_settings.country),

View File

@@ -40,8 +40,11 @@ export const middleware: NextMiddleware = async (request) => {
if (incomingPathNameParts.length >= 2) { if (incomingPathNameParts.length >= 2) {
const subpage = incomingPathNameParts.pop() const subpage = incomingPathNameParts.pop()
if (subpage) { if (subpage) {
const { contentType: parentContentType, uid: parentUid } = const {
await getUidAndContentTypeByPath(incomingPathNameParts.join("/")) contentType: parentContentType,
seoFilters,
uid: parentUid,
} = await getUidAndContentTypeByPath(incomingPathNameParts.join("/"))
if (parentUid) { if (parentUid) {
switch (parentContentType) { switch (parentContentType) {
@@ -53,8 +56,18 @@ export const middleware: NextMiddleware = async (request) => {
break break
case PageContentTypeEnum.destinationCityPage: case PageContentTypeEnum.destinationCityPage:
case PageContentTypeEnum.destinationCountryPage: case PageContentTypeEnum.destinationCountryPage:
// E.g. Active filters inside destination pages to filter hotels. // Validate Seo Filters from CMS and redirect if not found
if (!seoFilters?.includes(subpage)) {
return NextResponse.redirect(
new URL(incomingPathNameParts.join("/"), nextUrl),
{
status: 301,
}
)
}
// E.g. Active Seo filters inside destination pages to filter hotels.
searchParams.set("filterFromUrl", subpage) searchParams.set("filterFromUrl", subpage)
contentType = parentContentType contentType = parentContentType
uid = parentUid uid = parentUid
break break

View File

@@ -69,6 +69,17 @@ export const EntryByUrlBatch2 = gql`
} }
all_destination_country_page(where: { url: $url }, locale: $locale) { all_destination_country_page(where: { url: $url }, locale: $locale) {
items { items {
seo_filters {
filterConnection {
edges {
node {
... on HotelFilter {
slug
}
}
}
}
}
system { system {
...System ...System
} }
@@ -77,6 +88,17 @@ export const EntryByUrlBatch2 = gql`
} }
all_destination_city_page(where: { url: $url }, locale: $locale) { all_destination_city_page(where: { url: $url }, locale: $locale) {
items { items {
seo_filters {
filterConnection {
edges {
node {
... on HotelFilter {
slug
}
}
}
}
}
system { system {
...System ...System
} }

View File

@@ -11,10 +11,10 @@ export const getUidAndContentTypeByPath = async (pathname: string) => {
const contentTypePathName = pathWithoutTrailingSlash.replace(`/${lang}`, "") const contentTypePathName = pathWithoutTrailingSlash.replace(`/${lang}`, "")
const { contentType, uid, error } = await resolveEntry( const { contentType, seoFilters, uid, error } = await resolveEntry(
contentTypePathName, contentTypePathName,
lang ?? Lang.en lang ?? Lang.en
) )
return { contentType, uid, error } return { contentType, seoFilters, uid, error }
} }

View File

@@ -1,12 +1,37 @@
import z from "zod" import z from "zod"
const baseResolveSchema = z.object({
system: z.object({
content_type_uid: z.string(),
uid: z.string(),
}),
})
const entryResolveSchema = z.object({ const entryResolveSchema = z.object({
items: z.array(baseResolveSchema),
total: z.number(),
})
const allDestinationPageResolveSchema = z.object({
items: z.array( items: z.array(
z.object({ baseResolveSchema.extend({
system: z.object({ seo_filters: z
content_type_uid: z.string(), .array(
uid: z.string(), z.object({
}), filterConnection: z.object({
edges: z
.array(
z.object({
node: z.object({
slug: z.string(),
}),
})
)
.nullish(),
}),
})
)
.nullish(),
}) })
), ),
total: z.number(), total: z.number(),
@@ -22,8 +47,8 @@ export const validateEntryResolveSchema = z.object({
all_current_blocks_page: entryResolveSchema, all_current_blocks_page: entryResolveSchema,
all_hotel_page: entryResolveSchema, all_hotel_page: entryResolveSchema,
all_destination_overview_page: entryResolveSchema, all_destination_overview_page: entryResolveSchema,
all_destination_country_page: entryResolveSchema, all_destination_country_page: allDestinationPageResolveSchema,
all_destination_city_page: entryResolveSchema, all_destination_city_page: allDestinationPageResolveSchema,
all_start_page: entryResolveSchema, all_start_page: entryResolveSchema,
all_promo_campaign_page: entryResolveSchema, all_promo_campaign_page: entryResolveSchema,
}) })

View File

@@ -54,6 +54,17 @@ export async function resolve(url: string, lang = Lang.en) {
for (const value of Object.values(validatedData.data)) { for (const value of Object.values(validatedData.data)) {
if (value.total) { if (value.total) {
const { content_type_uid, uid } = value.items[0].system const { content_type_uid, uid } = value.items[0].system
const seoFilters =
"seo_filters" in value.items[0] ? value.items[0].seo_filters : null
if (seoFilters && seoFilters.length > 0) {
return {
contentType: content_type_uid,
uid,
seoFilters: seoFilters.flatMap((f) =>
f.filterConnection.edges?.flatMap((e) => e.node.slug)
),
}
}
return { return {
contentType: content_type_uid, contentType: content_type_uid,
uid, uid,