From 53b630b6d8cbcbd98d3c729ffee0f65eaf3238d9 Mon Sep 17 00:00:00 2001 From: Hrishikesh Vaipurkar Date: Fri, 2 May 2025 14:22:05 +0000 Subject: [PATCH] Merged in feat/SW-2308-family-friends-booking-rest (pull request #1916) feat: SW-2308 FnF code restriction added * feat: SW-2308 FnF code restriction added * feat: 2308 Optimized code Approved-by: Niclas Edenvin --- .../(standard)/details/page.tsx | 15 ++++++ .../FnFNotAllowedAlert.module.css | 6 +++ .../FnFNotAllowedAlert/FnFNotAllowedAlert.tsx | 22 +++++++++ .../HotelReservation/SelectHotel/index.tsx | 12 +++++ .../HotelReservation/SelectRate/index.tsx | 25 +++++++--- apps/scandic-web/constants/booking.ts | 2 + apps/scandic-web/middleware.ts | 2 + .../middlewares/familyAndFriends.ts | 46 +++++++++++++++++++ apps/scandic-web/package.json | 1 + yarn.lock | 33 +++++++++++++ 10 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 apps/scandic-web/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert.module.css create mode 100644 apps/scandic-web/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert.tsx create mode 100644 apps/scandic-web/middlewares/familyAndFriends.ts diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx index ca2f08674..35dbbdcee 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx @@ -1,7 +1,9 @@ +import { cookies } from "next/headers" import { notFound, redirect } from "next/navigation" import { Suspense } from "react" import { BookingErrorCodeEnum } from "@/constants/booking" +import { FamilyAndFriendsCodes } from "@/constants/booking" import { selectRate } from "@/constants/routes/hotelReservation" import { getBreakfastPackages, @@ -17,6 +19,7 @@ import RoomOne from "@/components/HotelReservation/EnterDetails/Room/One" import DesktopSummary from "@/components/HotelReservation/EnterDetails/Summary/Desktop" import MobileSummary from "@/components/HotelReservation/EnterDetails/Summary/Mobile" import EnterDetailsTrackingWrapper from "@/components/HotelReservation/EnterDetails/Tracking" +import FnFNotAllowedAlert from "@/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert" import RoomProvider from "@/providers/Details/RoomProvider" import EnterDetailsProvider from "@/providers/EnterDetailsProvider" import { convertSearchParamsToObj } from "@/utils/url" @@ -38,6 +41,18 @@ export default async function DetailsPage({ delete booking.modifyRateIndex } + if ( + booking.bookingCode && + FamilyAndFriendsCodes.includes(booking.bookingCode) + ) { + const cookieStore = cookies() + const isInValidFNF = cookieStore.get("sc")?.value !== "1" + + if (isInValidFNF) { + return + } + } + const breakfastInput = { adults: 1, fromDate: booking.fromDate, diff --git a/apps/scandic-web/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert.module.css b/apps/scandic-web/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert.module.css new file mode 100644 index 000000000..1df3eb7da --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert.module.css @@ -0,0 +1,6 @@ +.fnfMain { + max-width: var(--max-width-page); + margin: auto; + min-height: 30dvh; + padding: var(--Spacing-x5) 0; +} diff --git a/apps/scandic-web/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert.tsx b/apps/scandic-web/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert.tsx new file mode 100644 index 000000000..01462e869 --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert.tsx @@ -0,0 +1,22 @@ +import Alert from "@/components/TempDesignSystem/Alert" +import { getIntl } from "@/i18n" + +import styles from "./FnFNotAllowedAlert.module.css" + +import { AlertTypeEnum } from "@/types/enums/alert" + +export default async function FnFNotAllowedAlert() { + const intl = await getIntl() + + return ( +
+ +
+ ) +} diff --git a/apps/scandic-web/components/HotelReservation/SelectHotel/index.tsx b/apps/scandic-web/components/HotelReservation/SelectHotel/index.tsx index ecbaa274f..1f28f54af 100644 --- a/apps/scandic-web/components/HotelReservation/SelectHotel/index.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectHotel/index.tsx @@ -1,9 +1,11 @@ import stringify from "json-stable-stringify-without-jsonify" +import { cookies } from "next/headers" import { notFound } from "next/navigation" import { Suspense } from "react" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" +import { FamilyAndFriendsCodes } from "@/constants/booking" import { alternativeHotels, alternativeHotelsMap, @@ -21,6 +23,7 @@ import { getIntl } from "@/i18n" import { getHotelSearchDetails } from "@/utils/hotelSearchDetails" import { convertObjToSearchParams } from "@/utils/url" +import FnFNotAllowedAlert from "../FnFNotAllowedAlert/FnFNotAllowedAlert" import HotelCardListing from "../HotelCardListing" import BookingCodeFilter from "./BookingCodeFilter" import { getFiltersFromHotels, getHotels } from "./helpers" @@ -67,6 +70,15 @@ export default async function SelectHotel({ if (!city) return notFound() + if (bookingCode && FamilyAndFriendsCodes.includes(bookingCode)) { + const cookieStore = cookies() + const isInValidFNF = cookieStore.get("sc")?.value !== "1" + + if (isInValidFNF) { + return + } + } + const hotels = await getHotels( selectHotelParams, isAlternativeFor, diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/index.tsx index 83250b678..687a450db 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/index.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/index.tsx @@ -1,8 +1,9 @@ import stringify from "json-stable-stringify-without-jsonify" +import { cookies } from "next/headers" import { notFound } from "next/navigation" import { Suspense } from "react" -import { REDEMPTION } from "@/constants/booking" +import { FamilyAndFriendsCodes, REDEMPTION } from "@/constants/booking" import { getHotel } from "@/lib/trpc/memoizedRequests" import HotelInfoCard from "@/components/HotelReservation/SelectRate/HotelInfoCard" @@ -13,6 +14,7 @@ import { getHotelSearchDetails } from "@/utils/hotelSearchDetails" import { convertSearchParamsToObj } from "@/utils/url" import AvailabilityError from "./AvailabilityError" +import FnFNotAllowedAlert from "../FnFNotAllowedAlert/FnFNotAllowedAlert" import { getValidDates } from "./getValidDates" import { getTracking } from "./tracking" @@ -73,17 +75,26 @@ export default async function SelectRatePage({ const booking = convertSearchParamsToObj(searchParams) + let isInValidFNF = false + if (bookingCode && FamilyAndFriendsCodes.includes(bookingCode)) { + const cookieStore = cookies() + isInValidFNF = cookieStore.get("sc")?.value !== "1" + } const suspenseKey = stringify(searchParams) return ( <> - + {isInValidFNF ? ( + + ) : ( + + )} { webView, dateFormat, bookingFlow, + familyAndFriends, sasXScandic, cmsContent, redirect, diff --git a/apps/scandic-web/middlewares/familyAndFriends.ts b/apps/scandic-web/middlewares/familyAndFriends.ts new file mode 100644 index 000000000..58506ee5f --- /dev/null +++ b/apps/scandic-web/middlewares/familyAndFriends.ts @@ -0,0 +1,46 @@ +import { type NextMiddleware, NextResponse } from "next/server" + +import { getPublicNextURL } from "@/server/utils" + +import { findLang } from "@/utils/languages" + +import { getDefaultRequestHeaders } from "./utils" + +import type { MiddlewareMatcher } from "@/types/middleware" + +export const middleware: NextMiddleware = async (request) => { + const lang = findLang(request.nextUrl.pathname)! + const nextUrlPublic = getPublicNextURL(request) + const redirectUrl = new URL(`/${lang}`, nextUrlPublic) + + const key = request.nextUrl.searchParams.get("key") + const code = request.nextUrl.searchParams.get("code") + + const md5 = require("md5") + if ( + key && + code && + key === md5("scandic" + new Date().toISOString().substring(0, 10)) + ) { + const headers = new Headers() + // Set cookie for this device/user to be valid to use the FnF code for 3 days starting now + headers.append( + "set-cookie", + `sc=1; max-age=259200; Path=/; HttpOnly; SameSite=Lax` + ) + const redirectOpts = { + headers, + } + redirectUrl.searchParams.set("bookingCode", code) + return NextResponse.redirect(redirectUrl, redirectOpts) + } + + const headers = getDefaultRequestHeaders(request) + return NextResponse.redirect(redirectUrl, { + headers, + }) +} + +export const matcher: MiddlewareMatcher = (request) => { + return request.nextUrl.pathname === "/en/familyandfriends" +} diff --git a/apps/scandic-web/package.json b/apps/scandic-web/package.json index cbad11c74..b785f3ca1 100644 --- a/apps/scandic-web/package.json +++ b/apps/scandic-web/package.json @@ -91,6 +91,7 @@ "jsonwebtoken": "^9.0.2", "libphonenumber-js": "^1.10.60", "lodash-es": "^4.17.21", + "md5": "^2.3.0", "nanoid": "^5.0.9", "next": "^14.2.25", "next-auth": "5.0.0-beta.19", diff --git a/yarn.lock b/yarn.lock index 296b20cbc..5fc128593 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6452,6 +6452,7 @@ __metadata: lint-staged: "npm:^15.2.2" lodash-es: "npm:^4.17.21" material-symbols: "npm:^0.29.0" + md5: "npm:^2.3.0" nanoid: "npm:^5.0.9" netlify-plugin-cypress: "npm:^2.2.1" next: "npm:^14.2.25" @@ -10282,6 +10283,13 @@ __metadata: languageName: node linkType: hard +"charenc@npm:0.0.2": + version: 0.0.2 + resolution: "charenc@npm:0.0.2" + checksum: 10c0/a45ec39363a16799d0f9365c8dd0c78e711415113c6f14787a22462ef451f5013efae8a28f1c058f81fc01f2a6a16955f7a5fd0cd56247ce94a45349c89877d8 + languageName: node + linkType: hard + "check-error@npm:^2.1.1": version: 2.1.1 resolution: "check-error@npm:2.1.1" @@ -10938,6 +10946,13 @@ __metadata: languageName: node linkType: hard +"crypt@npm:0.0.2": + version: 0.0.2 + resolution: "crypt@npm:0.0.2" + checksum: 10c0/adbf263441dd801665d5425f044647533f39f4612544071b1471962209d235042fb703c27eea2795c7c53e1dfc242405173003f83cf4f4761a633d11f9653f18 + languageName: node + linkType: hard + "css-select@npm:^5.1.0": version: 5.1.0 resolution: "css-select@npm:5.1.0" @@ -14151,6 +14166,13 @@ __metadata: languageName: node linkType: hard +"is-buffer@npm:~1.1.6": + version: 1.1.6 + resolution: "is-buffer@npm:1.1.6" + checksum: 10c0/ae18aa0b6e113d6c490ad1db5e8df9bdb57758382b313f5a22c9c61084875c6396d50bbf49315f5b1926d142d74dfb8d31b40d993a383e0a158b15fea7a82234 + languageName: node + linkType: hard + "is-bun-module@npm:^1.0.2": version: 1.3.0 resolution: "is-bun-module@npm:1.3.0" @@ -16457,6 +16479,17 @@ __metadata: languageName: node linkType: hard +"md5@npm:^2.3.0": + version: 2.3.0 + resolution: "md5@npm:2.3.0" + dependencies: + charenc: "npm:0.0.2" + crypt: "npm:0.0.2" + is-buffer: "npm:~1.1.6" + checksum: 10c0/14a21d597d92e5b738255fbe7fe379905b8cb97e0a49d44a20b58526a646ec5518c337b817ce0094ca94d3e81a3313879c4c7b510d250c282d53afbbdede9110 + languageName: node + linkType: hard + "mdn-data@npm:2.0.28": version: 2.0.28 resolution: "mdn-data@npm:2.0.28"