) {
+ const isLangLive = useIsLangLive()
const lang = useLang()
const intl = useIntl()
const {
@@ -76,7 +78,7 @@ export default function MobileMenu({
})
const baseUrl = env.NEXT_PUBLIC_PUBLIC_URL || "https://www.scandichotels.com"
- const findMyBookingUrl = env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE
+ const findMyBookingUrl = !isLangLive
? getCurrentWebUrl({
path: findMyBookingCurrentWebPath[lang],
lang,
diff --git a/apps/scandic-web/components/Header/TopMenu/index.tsx b/apps/scandic-web/components/Header/TopMenu/index.tsx
index f7103f5c2..3c662ad14 100644
--- a/apps/scandic-web/components/Header/TopMenu/index.tsx
+++ b/apps/scandic-web/components/Header/TopMenu/index.tsx
@@ -34,7 +34,7 @@ export default async function TopMenu() {
const lang = getLang()
const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com"
- const findMyBookingUrl = env.HIDE_FOR_NEXT_RELEASE
+ const findMyBookingUrl = !env.isLangLive(lang)
? getCurrentWebUrl({
path: findMyBookingCurrentWebPath[lang],
lang,
diff --git a/apps/scandic-web/components/Header/index.tsx b/apps/scandic-web/components/Header/index.tsx
index 08bfd38dd..481e53851 100644
--- a/apps/scandic-web/components/Header/index.tsx
+++ b/apps/scandic-web/components/Header/index.tsx
@@ -4,6 +4,7 @@ import { env } from "@/env/server"
import { getHeader, getName } from "@/lib/trpc/memoizedRequests"
import CurrentHeader from "@/components/Current/Header"
+import { getLang } from "@/i18n/serverContext"
import HeaderFallback from "../Current/Header/HeaderFallback"
import MainMenu from "./MainMenu"
@@ -14,7 +15,8 @@ import styles from "./header.module.css"
export default function Header() {
void getName()
- if (env.HIDE_FOR_NEXT_RELEASE) {
+ const lang = getLang()
+ if (!env.isLangLive(lang)) {
return (
}>
diff --git a/apps/scandic-web/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx b/apps/scandic-web/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx
index a0d831fe2..c3e852e2f 100644
--- a/apps/scandic-web/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx
+++ b/apps/scandic-web/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx
@@ -28,9 +28,6 @@ export default function LanguageSwitcherContent({
const urlKeys = Object.keys(urls) as Lang[]
const pathname = usePathname()
- const relValue = env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE
- ? "nofollow"
- : undefined
return (
@@ -43,13 +40,14 @@ export default function LanguageSwitcherContent({
{urlKeys.map((key) => {
const url = urls[key]?.url
const isActive = currentLanguage === key
+
if (url) {
return (
diff --git a/apps/scandic-web/env/client.ts b/apps/scandic-web/env/client.ts
index 391cdfa8d..9df264b56 100644
--- a/apps/scandic-web/env/client.ts
+++ b/apps/scandic-web/env/client.ts
@@ -1,18 +1,24 @@
import { createEnv } from "@t3-oss/env-nextjs"
import { z } from "zod"
-export const env = createEnv({
+import { getLiveStatus } from "./getLiveStatus"
+import { isLangLive } from "./isLangLive"
+
+import type { Lang } from "@/constants/languages"
+
+const _env = createEnv({
client: {
NEXT_PUBLIC_NODE_ENV: z.enum(["development", "test", "production"]),
NEXT_PUBLIC_PORT: z.string().default("3000"),
NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.string().default("development"),
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE: z.coerce.number().default(0.001),
- NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE: z
+ NEXT_PUBLIC_NEW_SITE_LIVE_FOR_LANGS: z
.string()
- // only allow "true" or "false"
- .refine((s) => s === "true" || s === "false")
- // transform to boolean
- .transform((s) => s === "true"),
+ .regex(/^([a-z]{2},)*([a-z]{2}){0,1}$/)
+ .transform((val) => {
+ return val.split(",")
+ })
+ .default(""),
NEXT_PUBLIC_PUBLIC_URL: z.string().optional(),
},
emptyStringAsUndefined: true,
@@ -22,8 +28,15 @@ export const env = createEnv({
NEXT_PUBLIC_SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE:
process.env.NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE,
- NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE:
- process.env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE,
+ NEXT_PUBLIC_NEW_SITE_LIVE_FOR_LANGS:
+ process.env.NEXT_PUBLIC_NEW_SITE_LIVE_FOR_LANGS,
NEXT_PUBLIC_PUBLIC_URL: process.env.NEXT_PUBLIC_PUBLIC_URL,
},
})
+
+export const env = {
+ ..._env,
+ NEW_SITE_LIVE_STATUS: getLiveStatus(_env),
+ isLangLive: (lang: Lang) =>
+ isLangLive(lang, _env.NEXT_PUBLIC_NEW_SITE_LIVE_FOR_LANGS),
+}
diff --git a/apps/scandic-web/env/getLiveStatus.ts b/apps/scandic-web/env/getLiveStatus.ts
new file mode 100644
index 000000000..0552ebeb0
--- /dev/null
+++ b/apps/scandic-web/env/getLiveStatus.ts
@@ -0,0 +1,54 @@
+// Cannot use from "@/constants/languages" due to jiti
+import { Lang } from "../constants/languages"
+
+export function getLiveStatus(
+ internalEnv:
+ | {
+ NEW_SITE_LIVE_FOR_LANGS: string[]
+ }
+ | {
+ NEXT_PUBLIC_NEW_SITE_LIVE_FOR_LANGS: string[]
+ }
+): "ALL_LANGUAGES_LIVE" | "SOME_LANGUAGES_LIVE" | "NOT_LIVE" {
+ const configuredLangs = getConfiguredLangs(internalEnv)
+ if (!configuredLangs) {
+ return "NOT_LIVE"
+ }
+
+ const allLangs = Object.keys(Lang)
+ const liveLangs = allLangs.filter((lang) => configuredLangs.includes(lang))
+ if (liveLangs.length === 0) {
+ return "NOT_LIVE"
+ }
+
+ if (
+ liveLangs.length === allLangs.length &&
+ allLangs.every((lang) => liveLangs.includes(lang))
+ ) {
+ return "ALL_LANGUAGES_LIVE"
+ }
+
+ return "SOME_LANGUAGES_LIVE"
+}
+
+function getConfiguredLangs(env: T): string[] | undefined {
+ if (
+ !(
+ "NEW_SITE_LIVE_FOR_LANGS" in env ||
+ "NEXT_PUBLIC_NEW_SITE_LIVE_FOR_LANGS" in env
+ )
+ ) {
+ return undefined
+ }
+
+ const configuredLangs =
+ "NEW_SITE_LIVE_FOR_LANGS" in env
+ ? env.NEW_SITE_LIVE_FOR_LANGS
+ : env.NEXT_PUBLIC_NEW_SITE_LIVE_FOR_LANGS
+
+ if (!Array.isArray(configuredLangs)) {
+ throw new Error("Misconfigured environment variable, expected array")
+ }
+
+ return configuredLangs
+}
diff --git a/apps/scandic-web/env/isLangLive.test.ts b/apps/scandic-web/env/isLangLive.test.ts
new file mode 100644
index 000000000..aded7a297
--- /dev/null
+++ b/apps/scandic-web/env/isLangLive.test.ts
@@ -0,0 +1,18 @@
+import { describe, expect, it } from "@jest/globals"
+
+import { Lang } from "@/constants/languages"
+
+import { isLangLive } from "./isLangLive"
+
+describe("hideForNextRelease", () => {
+ it("should return true if en is part of live languages", () => {
+ expect(isLangLive(Lang.en, ["en", "sv"])).toBe(true)
+ expect(isLangLive(Lang.en, ["en"])).toBe(true)
+ })
+
+ it("should return false if en is not part of live languages", () => {
+ expect(isLangLive(Lang.en, [])).toBe(false)
+ expect(isLangLive(Lang.en, ["sv"])).toBe(false)
+ expect(isLangLive(Lang.en, ["sv,fi"])).toBe(false)
+ })
+})
diff --git a/apps/scandic-web/env/isLangLive.ts b/apps/scandic-web/env/isLangLive.ts
new file mode 100644
index 000000000..350ab7617
--- /dev/null
+++ b/apps/scandic-web/env/isLangLive.ts
@@ -0,0 +1,5 @@
+import type { Lang } from "@/constants/languages"
+
+export function isLangLive(lang: Lang, liveLangs: string[]): boolean {
+ return liveLangs.includes(lang)
+}
diff --git a/apps/scandic-web/env/server.ts b/apps/scandic-web/env/server.ts
index b34ab606a..39bc28218 100644
--- a/apps/scandic-web/env/server.ts
+++ b/apps/scandic-web/env/server.ts
@@ -1,9 +1,14 @@
import { createEnv } from "@t3-oss/env-nextjs"
import { z } from "zod"
+import { getLiveStatus } from "./getLiveStatus"
+import { isLangLive } from "./isLangLive"
+
+import type { Lang } from "../constants/languages"
+
const TWENTYFOUR_HOURS = 24 * 60 * 60
-export const env = createEnv({
+const _env = createEnv({
/**
* Due to t3-env only checking typeof window === "undefined"
* and Netlify running Deno, window is never "undefined"
@@ -107,19 +112,6 @@ export const env = createEnv({
GOOGLE_STATIC_MAP_SIGNATURE_SECRET: z.string(),
GOOGLE_DYNAMIC_MAP_ID: z.string(),
GOOGLE_STATIC_MAP_ID: z.string(),
- HIDE_FOR_NEXT_RELEASE: z
- .string()
- // only allow "true" or "false"
- .refine((s) => s === "true" || s === "false")
- // transform to boolean
- .transform((s) => s === "true"),
- ENABLE_BOOKING_FLOW: z
- .string()
- // only allow "true" or "false"
- .refine((s) => s === "true" || s === "false")
- // transform to boolean
- .transform((s) => s === "true")
- .default("true"),
ENABLE_BOOKING_WIDGET: z
.string()
// only allow "true" or "false"
@@ -127,13 +119,6 @@ export const env = createEnv({
// transform to boolean
.transform((s) => s === "true")
.default("false"),
- ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH: z
- .string()
- // only allow "true" or "false"
- .refine((s) => s === "true" || s === "false")
- // transform to boolean
- .transform((s) => s === "true")
- .default("true"),
ENABLE_SURPRISES: z
.string()
// only allow "true" or "false"
@@ -200,6 +185,17 @@ export const env = createEnv({
.transform((s) => s === "true")
.default("true"),
WARMUP_TOKEN: z.string().optional(),
+ /**
+ * Include the languages that should be hidden for the next release
+ * Should be in the format of "en,da,de,fi,no,sv" or empty
+ */
+ NEW_SITE_LIVE_FOR_LANGS: z
+ .string()
+ .regex(/^([a-z]{2},)*([a-z]{2}){0,1}$/)
+ .transform((val) => {
+ return val.split(",")
+ })
+ .default(""),
},
emptyStringAsUndefined: true,
runtimeEnv: {
@@ -268,12 +264,8 @@ export const env = createEnv({
process.env.GOOGLE_STATIC_MAP_SIGNATURE_SECRET,
GOOGLE_STATIC_MAP_ID: process.env.GOOGLE_STATIC_MAP_ID,
GOOGLE_DYNAMIC_MAP_ID: process.env.GOOGLE_DYNAMIC_MAP_ID,
- HIDE_FOR_NEXT_RELEASE: process.env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE,
USE_NEW_REWARD_MODEL: process.env.USE_NEW_REWARD_MODEL,
- ENABLE_BOOKING_FLOW: process.env.ENABLE_BOOKING_FLOW,
ENABLE_BOOKING_WIDGET: process.env.ENABLE_BOOKING_WIDGET,
- ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH:
- process.env.ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH,
ENABLE_SURPRISES: process.env.ENABLE_SURPRISES,
SHOW_SITE_WIDE_ALERT: process.env.SHOW_SITE_WIDE_ALERT,
SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
@@ -295,9 +287,16 @@ export const env = createEnv({
GIT_SHA: process.env.GIT_SHA,
ENABLE_WARMUP_HOTEL: process.env.ENABLE_WARMUP_HOTEL,
WARMUP_TOKEN: process.env.WARMUP_TOKEN,
+ NEW_SITE_LIVE_FOR_LANGS: process.env.NEXT_PUBLIC_NEW_SITE_LIVE_FOR_LANGS,
},
})
+export const env = {
+ ..._env,
+ NEW_SITE_LIVE_STATUS: getLiveStatus(_env),
+ isLangLive: (lang: Lang) => isLangLive(lang, _env.NEW_SITE_LIVE_FOR_LANGS),
+} as const
+
function replaceTopLevelDomain(url: string, domain: string) {
return url.replaceAll("{topleveldomain}", domain)
}
diff --git a/apps/scandic-web/hooks/useIsLangLive.ts b/apps/scandic-web/hooks/useIsLangLive.ts
new file mode 100644
index 000000000..87a254b42
--- /dev/null
+++ b/apps/scandic-web/hooks/useIsLangLive.ts
@@ -0,0 +1,10 @@
+"use client"
+
+import { env } from "@/env/client"
+
+import useLang from "./useLang"
+
+export function useIsLangLive(): boolean {
+ const lang = useLang()
+ return env.isLangLive(lang)
+}
diff --git a/apps/scandic-web/hooks/useStickyPosition.ts b/apps/scandic-web/hooks/useStickyPosition.ts
index e69eb45ed..f86ef54a4 100644
--- a/apps/scandic-web/hooks/useStickyPosition.ts
+++ b/apps/scandic-web/hooks/useStickyPosition.ts
@@ -2,7 +2,6 @@
import { useCallback, useEffect, useState } from "react"
-import { env } from "@/env/client"
import useStickyPositionStore, {
type StickyElement,
type StickyElementNameEnum,
@@ -10,6 +9,8 @@ import useStickyPositionStore, {
import { debounce } from "@/utils/debounce"
+import { useIsLangLive } from "./useIsLangLive"
+
interface UseStickyPositionProps {
ref?: React.RefObject
name?: StickyElementNameEnum
@@ -46,6 +47,7 @@ export default function useStickyPosition({
getAllElements,
} = useStickyPositionStore()
+ const isLangLive = useIsLangLive()
/* Used for Current mobile header since that doesn't use this hook.
*
* Instead, calculate if the mobile header is shown and add the height of
@@ -123,7 +125,7 @@ export default function useStickyPosition({
updateHeights()
// Only do this special handling if we have the current header
- if (env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE) {
+ if (!isLangLive) {
if (document.body.clientWidth > 950) {
setBaseTopOffset(0)
} else {
@@ -142,7 +144,7 @@ export default function useStickyPosition({
resizeObserver.unobserve(document.body)
}
}
- }, [updateHeights])
+ }, [updateHeights, isLangLive])
return {
currentHeight: ref?.current?.offsetHeight || null,
diff --git a/apps/scandic-web/middlewares/cmsContent.ts b/apps/scandic-web/middlewares/cmsContent.ts
index 181412699..4dcb4cf45 100644
--- a/apps/scandic-web/middlewares/cmsContent.ts
+++ b/apps/scandic-web/middlewares/cmsContent.ts
@@ -1,7 +1,5 @@
import { type NextMiddleware, NextResponse } from "next/server"
-import { notFound } from "@/server/errors/next"
-
import { getUidAndContentTypeByPath } from "@/services/cms/getUidAndContentTypeByPath"
import { findLang } from "@/utils/languages"
import { removeTrailingSlash } from "@/utils/url"
@@ -29,7 +27,7 @@ export const middleware: NextMiddleware = async (request) => {
if (!contentType || !uid) {
// Routes to subpages we need to check if the parent of the incomingPathName exists.
- // Then we considered the incomingPathName to be a subpage. These subpages do not live in the CMS.
+ // Then we considered the incomingPathName to be a subpage. These subpages do NOT_LIVE in the CMS.
const incomingPathNameParts = incomingPathName.split("/")
// If the incomingPathName has 2 or more parts, it could possibly be a subpage.
diff --git a/apps/scandic-web/server/routers/contentstack/metadata/query.ts b/apps/scandic-web/server/routers/contentstack/metadata/query.ts
index f366fdbe1..a9b5eed71 100644
--- a/apps/scandic-web/server/routers/contentstack/metadata/query.ts
+++ b/apps/scandic-web/server/routers/contentstack/metadata/query.ts
@@ -230,7 +230,7 @@ export const metadataQueryRouter = router({
if (metadata) {
if (alternates) {
// Hiding alternates until all languages are released in production
- if (!env.HIDE_FOR_NEXT_RELEASE) {
+ if (env.NEW_SITE_LIVE_STATUS === "ALL_LANGUAGES_LIVE") {
metadata.alternates = alternates
}
}
diff --git a/apps/scandic-web/server/routers/user/utils.ts b/apps/scandic-web/server/routers/user/utils.ts
index 03345564c..369519cbd 100644
--- a/apps/scandic-web/server/routers/user/utils.ts
+++ b/apps/scandic-web/server/routers/user/utils.ts
@@ -334,7 +334,7 @@ export async function updateStaysBookingUrl(
const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com"
// Construct Booking URL.
- const bookingUrl = env.HIDE_FOR_NEXT_RELEASE
+ const bookingUrl = !env.isLangLive(lang)
? new URL(
getCurrentWebUrl({
path: myBookingPath[lang],
diff --git a/apps/scandic-web/server/tokenManager.ts b/apps/scandic-web/server/tokenManager.ts
index 0044ed891..cb2e6fa30 100644
--- a/apps/scandic-web/server/tokenManager.ts
+++ b/apps/scandic-web/server/tokenManager.ts
@@ -11,9 +11,8 @@ export async function getServiceToken() {
const tracer = trace.getTracer("getServiceToken")
return await tracer.startActiveSpan("getServiceToken", async () => {
- const scopes = env.ENABLE_BOOKING_FLOW
- ? ["profile", "hotel", "booking", "package", "availability"]
- : ["profile"]
+ const scopes = ["profile", "hotel", "booking", "package", "availability"]
+
const cacheKey = getServiceTokenCacheKey(scopes)
const cacheClient = await getCacheClient()
const token = await getOrSetServiceTokenFromCache(cacheKey, scopes, tracer)