Merged in fix/LOY-222-find-my-booking-urls-for-prod (pull request #1817)

Fix(LOY-222): Find my booking url handling

* fix(LOY-222): adapt findMyBooking url based on HIDE_FOR_NEXT_RELEASE

* feat(LOY-222): add current web paths for findMyBooking in multiple languages

* refactor(LOY-222): better env and new url constructions

* refactor(LOY-222): decouple env var handling from getCurrentWebUrl

* fix(LOY-222): update findMyBooking URL construction to use baseUrl

* fix(LOY-222): simplify findMyBooking URL handling for new web urls

* fix(LOY-222): Update Finnish path for hotel reservation lookup

* refactor(LOY-222): rename PUBLIC_URL to NEXT_PUBLIC_PUBLIC_URL for consistency


Approved-by: Christian Andolf
Approved-by: Linus Flood
This commit is contained in:
Chuma Mcphoy (We Ahead)
2025-04-22 07:03:23 +00:00
parent ba2198b77f
commit 27aef3982e
13 changed files with 82 additions and 20 deletions

View File

@@ -43,9 +43,9 @@ NODE_OPTIONS="--openssl-legacy-provider"
// OPENSSL_MODULES="/var/lang/lib/ossl-modules" to enable legacy encryption support. // OPENSSL_MODULES="/var/lang/lib/ossl-modules" to enable legacy encryption support.
OPENSSL_MODULES="/var/lang/lib/ossl-modules" OPENSSL_MODULES="/var/lang/lib/ossl-modules"
PUBLIC_URL="http://localhost:3000" NEXT_PUBLIC_PUBLIC_URL="http://localhost:3000"
AUTH_URL="$PUBLIC_URL/api/web/auth" AUTH_URL="$NEXT_PUBLIC_PUBLIC_URL/api/web/auth"
NEXTAUTH_URL="$PUBLIC_URL/api/web/auth" NEXTAUTH_URL="$NEXT_PUBLIC_PUBLIC_URL/api/web/auth"
GOOGLE_STATIC_MAP_KEY="" GOOGLE_STATIC_MAP_KEY=""
GOOGLE_STATIC_MAP_SIGNATURE_SECRET="" GOOGLE_STATIC_MAP_SIGNATURE_SECRET=""

View File

@@ -20,7 +20,7 @@ CYPRESS_CURITY_PASSWORD="test"
CYPRESS_BASE_URL="test" CYPRESS_BASE_URL="test"
DEPLOY_PRIME_URL="test" DEPLOY_PRIME_URL="test"
NEXTAUTH_SECRET="test" NEXTAUTH_SECRET="test"
PUBLIC_URL="test" NEXT_PUBLIC_PUBLIC_URL="test"
NEXTAUTH_URL="test" NEXTAUTH_URL="test"
REVALIDATE_SECRET="test" REVALIDATE_SECRET="test"
SEAMLESS_LOGIN_DA="test" SEAMLESS_LOGIN_DA="test"

View File

@@ -13,9 +13,10 @@ import styles from "./emptyUpcomingStays.module.css"
export default async function EmptyUpcomingStaysBlock() { export default async function EmptyUpcomingStaysBlock() {
const intl = await getIntl() const intl = await getIntl()
const lang = getLang() const lang = getLang()
const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com"
const href = env.HIDE_FOR_NEXT_RELEASE const href = env.HIDE_FOR_NEXT_RELEASE
? getCurrentWebUrl("/", lang) ? getCurrentWebUrl({ path: "/", lang, baseUrl })
: `/${lang}` : `/${lang}`
return ( return (

View File

@@ -13,9 +13,10 @@ import styles from "./emptyUpcomingStays.module.css"
export default async function EmptyUpcomingStaysBlock() { export default async function EmptyUpcomingStaysBlock() {
const intl = await getIntl() const intl = await getIntl()
const lang = getLang() const lang = getLang()
const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com"
const href = env.HIDE_FOR_NEXT_RELEASE const href = env.HIDE_FOR_NEXT_RELEASE
? getCurrentWebUrl("/", lang) ? getCurrentWebUrl({ path: "/", lang, baseUrl })
: `/${lang}` : `/${lang}`
return ( return (

View File

@@ -4,9 +4,10 @@
import { usePathname } from "next/navigation" import { usePathname } from "next/navigation"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { findMyBooking } from "@/constants/routes/findMyBooking" import { findMyBookingCurrentWebPath } from "@/constants/routes/findMyBooking"
import { logout } from "@/constants/routes/handleAuth" import { logout } from "@/constants/routes/handleAuth"
import { myPages } from "@/constants/routes/myPages" import { myPages } from "@/constants/routes/myPages"
import { env } from "@/env/client"
import useDropdownStore from "@/stores/main-menu" import useDropdownStore from "@/stores/main-menu"
import Image from "@/components/Image" import Image from "@/components/Image"
@@ -16,6 +17,7 @@ import SkeletonShimmer from "@/components/SkeletonShimmer"
import Link from "@/components/TempDesignSystem/Link" import Link from "@/components/TempDesignSystem/Link"
import useLang from "@/hooks/useLang" import useLang from "@/hooks/useLang"
import { trackClick } from "@/utils/tracking" import { trackClick } from "@/utils/tracking"
import { getCurrentWebUrl } from "@/utils/url"
import BookingButton from "../BookingButton" import BookingButton from "../BookingButton"
@@ -38,6 +40,7 @@ export function MainMenu({
const intl = useIntl() const intl = useIntl()
const lang = useLang() const lang = useLang()
const pathname = usePathname() const pathname = usePathname()
const baseUrl = env.NEXT_PUBLIC_PUBLIC_URL || "https://www.scandichotels.com"
const isThreeStaticPagesPathnames = [ const isThreeStaticPagesPathnames = [
"/de/sponsoring", "/de/sponsoring",
@@ -157,7 +160,11 @@ export function MainMenu({
<li className={styles.mobileLinkRow}> <li className={styles.mobileLinkRow}>
<Link <Link
className={styles.mobileLinkButton} className={styles.mobileLinkButton}
href={findMyBooking[lang]} href={getCurrentWebUrl({
path: findMyBookingCurrentWebPath[lang],
lang,
baseUrl,
})}
> >
{intl.formatMessage({ {intl.formatMessage({
defaultMessage: "Find booking", defaultMessage: "Find booking",

View File

@@ -6,13 +6,18 @@ import { useIntl } from "react-intl"
import { useMediaQuery } from "usehooks-ts" import { useMediaQuery } from "usehooks-ts"
import { customerService } from "@/constants/currentWebHrefs" import { customerService } from "@/constants/currentWebHrefs"
import { findMyBooking } from "@/constants/routes/findMyBooking" import {
findMyBooking,
findMyBookingCurrentWebPath,
} from "@/constants/routes/findMyBooking"
import { env } from "@/env/client"
import useDropdownStore from "@/stores/main-menu" import useDropdownStore from "@/stores/main-menu"
import { IconName } from "@/components/Icons/iconName" import { IconName } from "@/components/Icons/iconName"
import LanguageSwitcher from "@/components/LanguageSwitcher" import LanguageSwitcher from "@/components/LanguageSwitcher"
import { useHandleKeyUp } from "@/hooks/useHandleKeyUp" import { useHandleKeyUp } from "@/hooks/useHandleKeyUp"
import useLang from "@/hooks/useLang" import useLang from "@/hooks/useLang"
import { getCurrentWebUrl } from "@/utils/url"
import HeaderLink from "../../HeaderLink" import HeaderLink from "../../HeaderLink"
import TopLink from "../../TopLink" import TopLink from "../../TopLink"
@@ -70,6 +75,15 @@ export default function MobileMenu({
defaultMessage: "Open menu", defaultMessage: "Open menu",
}) })
const baseUrl = env.NEXT_PUBLIC_PUBLIC_URL || "https://www.scandichotels.com"
const findMyBookingUrl = env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE
? getCurrentWebUrl({
path: findMyBookingCurrentWebPath[lang],
lang,
baseUrl,
})
: findMyBooking[lang]
return ( return (
<> <>
<button <button
@@ -90,7 +104,7 @@ export default function MobileMenu({
{children} {children}
<footer className={styles.footer}> <footer className={styles.footer}>
<HeaderLink <HeaderLink
href={findMyBooking[lang]} href={findMyBookingUrl}
iconName={IconName.Search} iconName={IconName.Search}
onClick={() => toggleDropdown(DropdownTypeEnum.HamburgerMenu)} onClick={() => toggleDropdown(DropdownTypeEnum.HamburgerMenu)}
> >

View File

@@ -1,4 +1,8 @@
import { findMyBooking } from "@/constants/routes/findMyBooking" import {
findMyBooking,
findMyBookingCurrentWebPath,
} from "@/constants/routes/findMyBooking"
import { env } from "@/env/server"
import { getHeader } from "@/lib/trpc/memoizedRequests" import { getHeader } from "@/lib/trpc/memoizedRequests"
import { auth } from "@/auth" import { auth } from "@/auth"
@@ -9,6 +13,7 @@ import Caption from "@/components/TempDesignSystem/Text/Caption"
import { getIntl } from "@/i18n" import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext" import { getLang } from "@/i18n/serverContext"
import { isValidSession } from "@/utils/session" import { isValidSession } from "@/utils/session"
import { getCurrentWebUrl } from "@/utils/url"
import HeaderLink from "../HeaderLink" import HeaderLink from "../HeaderLink"
import TopLink from "../TopLink" import TopLink from "../TopLink"
@@ -28,6 +33,14 @@ export default async function TopMenu() {
} }
const lang = getLang() const lang = getLang()
const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com"
const findMyBookingUrl = env.HIDE_FOR_NEXT_RELEASE
? getCurrentWebUrl({
path: findMyBookingCurrentWebPath[lang],
lang,
baseUrl,
})
: findMyBooking[lang]
return ( return (
<div className={styles.topMenu}> <div className={styles.topMenu}>
@@ -37,7 +50,7 @@ export default async function TopMenu() {
<LanguageSwitcher type="desktopHeader" /> <LanguageSwitcher type="desktopHeader" />
<Caption type="regular" color="textMediumContrast" asChild> <Caption type="regular" color="textMediumContrast" asChild>
<HeaderLink href={findMyBooking[lang]} iconName={IconName.Search}> <HeaderLink href={findMyBookingUrl} iconName={IconName.Search}>
{intl.formatMessage({ {intl.formatMessage({
defaultMessage: "Find booking", defaultMessage: "Find booking",
})} })}

View File

@@ -88,7 +88,7 @@ export async function MyStay({ refId }: { refId: string }) {
const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com" const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com"
const promoUrl = env.HIDE_FOR_NEXT_RELEASE const promoUrl = env.HIDE_FOR_NEXT_RELEASE
? new URL(getCurrentWebUrl("/", lang)) ? new URL(getCurrentWebUrl({ path: "/", lang, baseUrl }))
: new URL(`${baseUrl}/${lang}/`) : new URL(`${baseUrl}/${lang}/`)
promoUrl.searchParams.set("hotel", hotel.operaId) promoUrl.searchParams.set("hotel", hotel.operaId)

View File

@@ -12,3 +12,13 @@ export const findMyBooking = {
no: "/no/hotelreservation/get-booking", no: "/no/hotelreservation/get-booking",
sv: "/sv/hotelreservation/hitta-bokning", sv: "/sv/hotelreservation/hitta-bokning",
} }
/** @type {import('@/types/routes').LangRoute} */
export const findMyBookingCurrentWebPath = {
da: "/hotelreservation/hent-booking",
de: "/hotelreservation/mein-bereich",
en: "/hotelreservation/get-booking",
fi: "/varaa-hotelli/hae-varaus",
no: "/hotelreservation/get-booking",
sv: "/hotelreservation/hitta-bokning",
}

View File

@@ -13,6 +13,7 @@ export const env = createEnv({
.refine((s) => s === "true" || s === "false") .refine((s) => s === "true" || s === "false")
// transform to boolean // transform to boolean
.transform((s) => s === "true"), .transform((s) => s === "true"),
NEXT_PUBLIC_PUBLIC_URL: z.string().optional(),
}, },
emptyStringAsUndefined: true, emptyStringAsUndefined: true,
runtimeEnv: { runtimeEnv: {
@@ -23,5 +24,6 @@ export const env = createEnv({
process.env.NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE, process.env.NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE,
NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE: NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE:
process.env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE, process.env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE,
NEXT_PUBLIC_PUBLIC_URL: process.env.NEXT_PUBLIC_PUBLIC_URL,
}, },
}) })

View File

@@ -231,7 +231,7 @@ export const env = createEnv({
AUTH_URL: process.env.AUTH_URL, AUTH_URL: process.env.AUTH_URL,
NODE_ENV: process.env.NODE_ENV, NODE_ENV: process.env.NODE_ENV,
PRINT_QUERY: process.env.PRINT_QUERY, PRINT_QUERY: process.env.PRINT_QUERY,
PUBLIC_URL: process.env.PUBLIC_URL, PUBLIC_URL: process.env.NEXT_PUBLIC_PUBLIC_URL,
REVALIDATE_SECRET: process.env.REVALIDATE_SECRET, REVALIDATE_SECRET: process.env.REVALIDATE_SECRET,
SITEMAP_SYNC_SECRET: process.env.SITEMAP_SYNC_SECRET, SITEMAP_SYNC_SECRET: process.env.SITEMAP_SYNC_SECRET,
SALESFORCE_PREFERENCE_BASE_URL: process.env.SALESFORCE_PREFERENCE_BASE_URL, SALESFORCE_PREFERENCE_BASE_URL: process.env.SALESFORCE_PREFERENCE_BASE_URL,

View File

@@ -75,7 +75,13 @@ async function updateStaysBookingUrl(
// Construct Booking URL. // Construct Booking URL.
const bookingUrl = env.HIDE_FOR_NEXT_RELEASE const bookingUrl = env.HIDE_FOR_NEXT_RELEASE
? new URL(getCurrentWebUrl(myBookingPath[lang], lang)) ? new URL(
getCurrentWebUrl({
path: myBookingPath[lang],
lang,
baseUrl,
})
)
: new URL(myStay[lang], baseUrl) : new URL(myStay[lang], baseUrl)
// Add search parameters. // Add search parameters.

View File

@@ -1,5 +1,4 @@
import { Lang } from "@/constants/languages" import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import type { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" import type { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import type { import type {
@@ -192,12 +191,21 @@ export function getTldForLanguage(lang: Lang): string {
/** /**
* Constructs a URL with the correct TLD (top-level domain) based on lang, for current web. * Constructs a URL with the correct TLD (top-level domain) based on lang, for current web.
* @param path - The path to append to the URL * @param params - Object containing path, lang, and baseUrl
* @param lang - The language to use for TLD * @param params.path - The path to append to the URL
* @param params.lang - The language to use for TLD
* @param params.baseUrl - The base URL to use (e.g. https://www.scandichotels.com)
* @returns The complete URL with language-specific TLD * @returns The complete URL with language-specific TLD
*/ */
export function getCurrentWebUrl(path: string, lang: Lang): string { export function getCurrentWebUrl({
const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com" // Fallback for ephemeral environments (e.g. deploy previews). path,
lang,
baseUrl = "https://www.scandichotels.com", // Fallback for ephemeral environments (e.g. deploy previews).
}: {
path: string
lang: Lang
baseUrl?: string
}): string {
const tld = getTldForLanguage(lang) const tld = getTldForLanguage(lang)
const url = new URL(path, baseUrl) const url = new URL(path, baseUrl)