Merged in feat/sw-2859-set-up-shared-trpc-package (pull request #2319)

feat(SW-2859): Create trpc package

* Add isEdge, safeTry and dataCache to new common package

* Add eslint and move prettier config

* Clean up tests

* Create trpc package and move initialization

* Move errors and a few procedures

* Move telemetry to common package

* Move tokenManager to common package

* Add Sentry to procedures

* Clean up procedures

* Fix self-referencing imports

* Add exports to packages and lint rule to prevent relative imports

* Add env to trpc package

* Add eslint to trpc package

* Apply lint rules

* Use direct imports from trpc package

* Add lint-staged config to trpc

* Move lang enum to common

* Restructure trpc package folder structure

* Fix lang imports


Approved-by: Linus Flood
This commit is contained in:
Anton Gunnarsson
2025-06-18 12:14:20 +00:00
parent 2f38bdf0b1
commit 846fd904a6
211 changed files with 989 additions and 627 deletions

View File

@@ -1,7 +1,8 @@
import { type NextRequest, NextResponse } from "next/server"
import { AuthError } from "next-auth"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { env } from "@/env/server"
import { internalServerError } from "@/server/errors/next"
import { getPublicURL } from "@/server/utils"

View File

@@ -1,5 +1,7 @@
import { notFound } from "next/navigation"
import { getServiceToken } from "@scandic-hotels/common/tokenManager"
import {
BookingErrorCodeEnum,
PaymentCallbackStatusEnum,
@@ -10,7 +12,6 @@ import {
} from "@/constants/routes/hotelReservation"
import { serverClient } from "@/lib/trpc/server"
import { getBooking } from "@/server/routers/booking/utils"
import { getServiceToken } from "@/server/tokenManager"
import { auth } from "@/auth"
import HandleErrorCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/HandleErrorCallback"

View File

@@ -1,7 +1,8 @@
import { type NextRequest, NextResponse } from "next/server"
import { AuthError } from "next-auth"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { env } from "@/env/server"
import { internalServerError } from "@/server/errors/next"
import { getPublicURL } from "@/server/utils"

View File

@@ -6,7 +6,7 @@ import { getPublicURL } from "@/server/utils"
import { signIn } from "@/auth"
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
export async function GET(
request: NextRequest,

View File

@@ -5,9 +5,10 @@ import { useParams, useRouter, useSearchParams } from "next/navigation"
import { startTransition, useEffect, useRef } from "react"
import { useIntl } from "react-intl"
import { SESSION_EXPIRED } from "@scandic-hotels/trpc/errors"
import { login } from "@/constants/routes/handleAuth"
import { env } from "@/env/client"
import { SESSION_EXPIRED } from "@/server/errors/trpc"
import styles from "./error.module.css"

View File

@@ -7,7 +7,8 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
import Script from "next/script"
import { SessionProvider } from "next-auth/react"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import TrpcProvider from "@/lib/trpc/Provider"
import { SessionRefresher } from "@/components/Auth/TokenRefresher"

View File

@@ -7,7 +7,7 @@ import "@scandic-hotels/design-system/style.css"
import Script from "next/script"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import TokenRefresher from "@/components/Auth/TokenRefresher"
import CookieBotConsent from "@/components/CookieBot"
@@ -35,12 +35,9 @@ export default async function RootLayout(
LayoutArgs<LangParams> & { header: React.ReactNode }
>
) {
const params = await props.params;
const params = await props.params
const {
children,
header
} = props;
const { children, header } = props
setLang(params.lang)
const messages = await getMessages(params.lang)

View File

@@ -7,7 +7,8 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
import Script from "next/script"
import { SessionProvider } from "next-auth/react"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import TrpcProvider from "@/lib/trpc/Provider"
import { SessionRefresher } from "@/components/Auth/TokenRefresher"
@@ -23,12 +24,12 @@ import { setLang } from "@/i18n/serverContext"
import type { LangParams, LayoutArgs } from "@/types/params"
export default async function RootLayout(props: React.PropsWithChildren<LayoutArgs<LangParams>>) {
const params = await props.params;
export default async function RootLayout(
props: React.PropsWithChildren<LayoutArgs<LangParams>>
) {
const params = await props.params
const {
children
} = props;
const { children } = props
setLang(params.lang)
const messages = await getMessages(params.lang)

View File

@@ -14,8 +14,9 @@ import { getIntl } from "@/i18n"
import { SASModal } from "../components/SASModal"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { LangParams, PageArgs, SearchParams } from "@/types/params"
import type { Lang } from "@/constants/languages"
import type { State } from "../sasUtils"
const searchParamsSchema = z.object({
@@ -24,9 +25,11 @@ const searchParamsSchema = z.object({
type Intent = z.infer<typeof searchParamsSchema>["intent"]
export default async function SASxScandicLoginPage(props: PageArgs<LangParams> & SearchParams) {
const params = await props.params;
const searchParams = await props.searchParams;
export default async function SASxScandicLoginPage(
props: PageArgs<LangParams> & SearchParams
) {
const params = await props.params
const searchParams = await props.searchParams
const result = searchParamsSchema.safeParse(searchParams)
if (!result.success) {
// TOOD where to redirect?

View File

@@ -14,10 +14,10 @@ import OneTimePasswordForm, {
type OnSubmitHandler,
} from "./OneTimePasswordForm"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { ReactNode } from "react"
import type { LangParams, PageArgs, SearchParams } from "@/types/params"
import type { Lang } from "@/constants/languages"
const otpError = z.enum(["invalidCode", "expiredCode"])
const intent = z.enum(["link", "unlink", "transfer"])

View File

@@ -17,8 +17,9 @@ import { SASModal } from "../../components/SASModal"
import styles from "./transferSuccess.module.css"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { LangParams, PageArgs, SearchParams } from "@/types/params"
import type { Lang } from "@/constants/languages"
export default async function SASxScandicTransferSuccessPage(
props: PageArgs<LangParams> & SearchParams<{ p?: string }>

View File

@@ -6,7 +6,8 @@ import "@scandic-hotels/design-system/style.css"
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
import Script from "next/script"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { env } from "@/env/server"
import TrpcProvider from "@/lib/trpc/Provider"

View File

@@ -5,7 +5,8 @@ import "@scandic-hotels/design-system/style.css"
import Script from "next/script"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import TrpcProvider from "@/lib/trpc/Provider"
import { ToastHandler } from "@/components/TempDesignSystem/Toasts"

View File

@@ -1,4 +1,5 @@
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { profile } from "@/constants/routes/myPages"
import { serverClient } from "@/lib/trpc/server"
import { getPublicURL } from "@/server/utils"

View File

@@ -2,9 +2,9 @@ import { revalidateTag } from "next/cache"
import { headers } from "next/headers"
import { z } from "zod"
import { Lang } from "@scandic-hotels/common/constants/language"
import { getCacheClient } from "@scandic-hotels/common/dataCache"
import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import { badRequest, internalServerError, notFound } from "@/server/errors/next"

View File

@@ -2,9 +2,9 @@ import { revalidateTag } from "next/cache"
import { headers } from "next/headers"
import { z } from "zod"
import { Lang } from "@scandic-hotels/common/constants/language"
import { getCacheClient } from "@scandic-hotels/common/dataCache"
import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import { badRequest, internalServerError, notFound } from "@/server/errors/next"

View File

@@ -8,7 +8,7 @@ import { badRequest, internalServerError } from "@/server/errors/next"
import { generateTag } from "@/utils/generateTag"
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
// This file is primarily to be used locally to test
// purging your cache for new (and old) requests

View File

@@ -2,9 +2,9 @@ import { revalidateTag } from "next/cache"
import { headers } from "next/headers"
import { z } from "zod"
import { Lang } from "@scandic-hotels/common/constants/language"
import { getCacheClient } from "@scandic-hotels/common/dataCache"
import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import { badRequest, internalServerError } from "@/server/errors/next"
import { affix as breadcrumbsAffix } from "@/server/routers/contentstack/breadcrumbs/utils"

View File

@@ -1,8 +1,9 @@
import { type NextRequest, NextResponse } from "next/server"
import { createCounter } from "@scandic-hotels/common/telemetry"
import { env } from "@/env/server"
import { dt } from "@/lib/dt"
import { createCounter } from "@/server/telemetry"
import {
getEntries,

View File

@@ -1,7 +1,8 @@
import { Region, Stack } from "contentstack"
import { createCounter } from "@scandic-hotels/common/telemetry"
import { env } from "@/env/server"
import { createCounter } from "@/server/telemetry"
import type { SyncResponse } from "@/types/sitemap"

View File

@@ -1,10 +1,12 @@
import { createCounter } from "@scandic-hotels/common/telemetry"
import { env } from "@/env/server"
import { createCounter } from "@/server/telemetry"
import { removeTrailingSlash } from "@/utils/url"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { SyncItem } from "@/types/sitemap"
import type { Lang } from "@/constants/languages"
export function mergeEntries(
currentEntries: SyncItem[],

View File

@@ -1,11 +1,11 @@
import { fetchRequestHandler } from "@trpc/server/adapters/fetch"
import { createAppContext } from "@/lib/trpc/server"
import { appRouter } from "@/server"
import { createContext } from "@/server/context"
async function handler(req: Request) {
return fetchRequestHandler({
createContext,
createContext: createAppContext,
endpoint: "/api/web/trpc",
req,
router: appRouter,

View File

@@ -1,4 +1,5 @@
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { dt } from "@/lib/dt"
import Body from "@/components/TempDesignSystem/Text/Body"

View File

@@ -12,7 +12,7 @@ import { TransferPointsFormClient } from "./TransferPointsFormClient"
import styles from "./transferPoints.module.css"
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
export async function TransferPointsForm({ lang }: { lang: Lang }) {
const profile = await getProfileWithExtendedPartnerData()

View File

@@ -26,8 +26,9 @@ import Button from "@/components/TempDesignSystem/Button"
import styles from "./transferPoints.module.css"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { LangParams } from "@/types/params"
import type { Lang } from "@/constants/languages"
type TransferPointsFormClientProps = {
sasPoints: number | null

View File

@@ -4,7 +4,7 @@ import "dialogshift-webchat-sdk/bundles/dialogshift-webchat-sdk.min.css"
import { useEffect, useRef } from "react"
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
interface DialogshiftWidgetClientProps {
widgetId: string

View File

@@ -1,3 +1,4 @@
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { IntlShape } from "react-intl"
import { HealthFacilitiesEnum } from "@/types/components/hotelPage/facilities"
@@ -13,7 +14,6 @@ import {
import { HotelHashValues } from "@/types/enums/hotelPage"
import type { Hotel, HotelData } from "@/types/hotel"
import type { HotelPage } from "@/types/trpc/routers/contentstack/hotelPage"
import type { Lang } from "@/constants/languages"
export function getRoomNameAsParam(roomName: string) {
return roomName

View File

@@ -1,6 +1,6 @@
/* eslint-disable formatjs/no-literal-string-in-jsx */
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import styles from "./contact.module.css"

View File

@@ -3,7 +3,7 @@
"use client"
import { useCallback, useEffect, useRef, useState } from "react"
import { type Lang, languages } from "@/constants/languages"
import { languages } from "@/constants/languages"
import { env } from "@/env/client"
import Link from "@/components/TempDesignSystem/Link"
@@ -11,6 +11,8 @@ import useLang from "@/hooks/useLang"
import styles from "./desktop.module.css"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { LanguageSwitcherProps } from "@/types/components/current/languageSwitcher"
export default function Desktop({ urls }: LanguageSwitcherProps) {

View File

@@ -3,13 +3,15 @@
"use client"
import { useState } from "react"
import { type Lang, languages } from "@/constants/languages"
import { languages } from "@/constants/languages"
import { env } from "@/env/client"
import useLang from "@/hooks/useLang"
import styles from "./mobile.module.css"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { LanguageSwitcherProps } from "@/types/components/current/languageSwitcher"
export default function Mobile({ urls }: LanguageSwitcherProps) {

View File

@@ -2,7 +2,9 @@
import { headers } from "next/headers"
import { Lang, localeToLang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { localeToLang } from "@/constants/languages"
import { getLang } from "@/i18n/serverContext"

View File

@@ -1,4 +1,4 @@
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
type Texts = {
title: string

View File

@@ -4,11 +4,11 @@ import { useState } from "react"
import { DayPicker } from "react-day-picker"
import { useIntl } from "react-intl"
import { Lang } from "@scandic-hotels/common/constants/language"
import { Divider } from "@scandic-hotels/design-system/Divider"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { Lang } from "@/constants/languages"
import { dt } from "@/lib/dt"
import Button from "@/components/TempDesignSystem/Button"

View File

@@ -3,10 +3,10 @@ import { useEffect, useRef, useState } from "react"
import { type DateRange, DayPicker } from "react-day-picker"
import { useIntl } from "react-intl"
import { Lang } from "@scandic-hotels/common/constants/language"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { Lang } from "@/constants/languages"
import { dt } from "@/lib/dt"
import Button from "@/components/TempDesignSystem/Button"

View File

@@ -4,10 +4,10 @@ import { useState } from "react"
import { DayPicker } from "react-day-picker"
import { useIntl } from "react-intl"
import { Lang } from "@scandic-hotels/common/constants/language"
import { Divider } from "@scandic-hotels/design-system/Divider"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Lang } from "@/constants/languages"
import { dt } from "@/lib/dt"
import Button from "@/components/TempDesignSystem/Button"

View File

@@ -2,7 +2,8 @@
import { DayPicker } from "react-day-picker"
import { useIntl } from "react-intl"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { dt } from "@/lib/dt"
import Button from "@/components/TempDesignSystem/Button"

View File

@@ -1,6 +1,6 @@
import { da, de, fi, nb, sv } from "date-fns/locale"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
export const locales = {
[Lang.da]: da,

View File

@@ -5,11 +5,7 @@ import { useEffect, useState } from "react"
import { FormProvider, useForm } from "react-hook-form"
import { useIntl } from "react-intl"
import {
getDefaultCountryFromLang,
type Lang,
langToApiLang,
} from "@/constants/languages"
import { getDefaultCountryFromLang, langToApiLang } from "@/constants/languages"
import { logout } from "@/constants/routes/handleAuth"
import { profile } from "@/constants/routes/myPages"
import { trpc } from "@/lib/trpc/client"
@@ -28,6 +24,8 @@ import { type EditProfileSchema, editProfileSchema } from "./schema"
import styles from "./form.module.css"
import type { Lang } from "@scandic-hotels/common/constants/language"
import {
type EditFormProps,
Status,

View File

@@ -6,6 +6,8 @@ import { getSpecialRoomType } from "@/utils/specialRoomType"
import { invertedBedTypeMap } from "../../utils"
import type { Lang } from "@scandic-hotels/common/constants/language"
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import {
TrackingChannelEnum,
@@ -20,7 +22,6 @@ import { RateEnum } from "@/types/enums/rate"
import type { Room } from "@/types/stores/booking-confirmation"
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
import type { RateDefinition } from "@/types/trpc/routers/hotel/roomAvailability"
import type { Lang } from "@/constants/languages"
function getRate(cancellationRule: RateDefinition["cancellationRule"] | null) {
switch (cancellationRule) {

View File

@@ -2,7 +2,7 @@
// import { act, cleanup, render, screen, within } from "@testing-library/react"
// import { type IntlConfig, IntlProvider } from "react-intl"
// import { Lang } from "@/constants/languages"
// import { Lang } from "@scandic-hotels/common/constants/language"
// import {
// bedType,

View File

@@ -7,10 +7,11 @@ import { useSearchHistory } from "@/hooks/useSearchHistory"
import { getTracking } from "./tracking"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { DetailsBooking } from "@/types/components/hotelReservation/enterDetails/details"
import type { Hotel } from "@/types/hotel"
import type { Room } from "@/types/providers/details/room"
import type { Lang } from "@/constants/languages"
interface TrackingWrapperProps {
booking: DetailsBooking

View File

@@ -5,6 +5,8 @@ import { REDEMPTION } from "@/constants/booking"
import { sumPackages } from "@/components/HotelReservation/utils"
import { getSpecialRoomType } from "@/utils/specialRoomType"
import type { Lang } from "@scandic-hotels/common/constants/language"
import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"
import type { BreakfastPackages } from "@/types/components/hotelReservation/breakfast"
import type { DetailsBooking } from "@/types/components/hotelReservation/enterDetails/details"
@@ -24,7 +26,6 @@ import type {
PriceProduct,
Product,
} from "@/types/trpc/routers/hotel/roomAvailability"
import type { Lang } from "@/constants/languages"
export function getTracking(
booking: DetailsBooking,

View File

@@ -37,10 +37,11 @@ import { hotelCardVariants } from "./variants"
import styles from "./hotelCard.module.css"
import type { Lang } from "@scandic-hotels/common/constants/language"
import { HotelCardListingTypeEnum } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import type { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps"
import { SidePeekEnum } from "@/types/components/hotelReservation/sidePeek"
import type { Lang } from "@/constants/languages"
function HotelCard({
hotelData: { availability, hotel },

View File

@@ -15,7 +15,7 @@ import {
trackAncillarySuccess,
} from "@/utils/tracking/myStay"
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
export default function GuaranteeAncillaryHandler({
confirmationNumber,

View File

@@ -16,7 +16,7 @@ import PriceAndDate from "./PriceAndDate"
import styles from "./confirmation.module.css"
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
interface ConfirmationProps {
checkInDate: string

View File

@@ -1,12 +1,13 @@
import { differenceInCalendarDays, format, isWeekend } from "date-fns"
import type { Lang } from "@scandic-hotels/common/constants/language"
import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"
import {
TrackingChannelEnum,
type TrackingSDKHotelInfo,
type TrackingSDKPageData,
} from "@/types/components/tracking"
import type { Lang } from "@/constants/languages"
import type { ChildrenInRoom } from "@/utils/hotelSearchDetails"
export function getTracking(

View File

@@ -1,12 +1,13 @@
import { differenceInCalendarDays, format, isWeekend } from "date-fns"
import type { Lang } from "@scandic-hotels/common/constants/language"
import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"
import {
TrackingChannelEnum,
type TrackingSDKHotelInfo,
type TrackingSDKPageData,
} from "@/types/components/tracking"
import type { Lang } from "@/constants/languages"
import type { ChildrenInRoom } from "@/utils/hotelSearchDetails"
export function getTracking(

View File

@@ -1,5 +1,7 @@
import { differenceInCalendarDays, format, isWeekend } from "date-fns"
import type { Lang } from "@scandic-hotels/common/constants/language"
import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import type { Room } from "@/types/components/hotelReservation/selectRate/selectRate"
@@ -8,7 +10,6 @@ import {
type TrackingSDKHotelInfo,
type TrackingSDKPageData,
} from "@/types/components/tracking"
import type { Lang } from "@/constants/languages"
import type { ChildrenInRoom } from "@/utils/hotelSearchDetails"
export function getTracking(

View File

@@ -12,8 +12,9 @@ import FnFNotAllowedAlert from "../FnFNotAllowedAlert/FnFNotAllowedAlert"
import AvailabilityError from "./AvailabilityError"
import Tracking from "./Tracking"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { SelectRateBooking } from "@/types/components/hotelReservation/selectRate/selectRate"
import type { Lang } from "@/constants/languages"
export default async function SelectRatePage({
lang,

View File

@@ -6,7 +6,7 @@ import { useIntl } from "react-intl"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { type Lang, languages } from "@/constants/languages"
import { languages } from "@/constants/languages"
import { env } from "@/env/client"
import Link from "@/components/TempDesignSystem/Link"
@@ -17,6 +17,8 @@ import { replaceUrlPart } from "./utils"
import styles from "./languageSwitcherContent.module.css"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { LanguageSwitcherContentProps } from "@/types/components/languageSwitcher/languageSwitcher"
export default function LanguageSwitcherContent({

View File

@@ -1,9 +1,10 @@
import { Lang } from "@scandic-hotels/common/constants/language"
import { Divider } from "@scandic-hotels/design-system/Divider"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { countriesMap } from "@/constants/countries"
import { Lang, languages } from "@/constants/languages"
import { languages } from "@/constants/languages"
import { profileEdit } from "@/constants/routes/myPages"
import { getProfile } from "@/lib/trpc/memoizedRequests"

View File

@@ -5,7 +5,8 @@ import { render, screen } from "@testing-library/react"
import { type UserEvent, userEvent } from "@testing-library/user-event"
import { FormProvider, useForm } from "react-hook-form"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { dt } from "@/lib/dt"
import { getLocalizedMonthName } from "@/utils/dateFormatting"

View File

@@ -1,5 +1,3 @@
import { Lang } from "./languages"
/**
* Contact support information (phone numbers and emails) by language.
*
@@ -9,6 +7,8 @@ import { Lang } from "./languages"
* potential support queries.
*/
import { Lang } from "@scandic-hotels/common/constants/language"
const mainNumber = "+46 8 517 517 00"
export const supportPhone: Record<Lang, string> = {

View File

@@ -1,13 +1,6 @@
import type { LowerCaseCountryCode } from "@/types/components/form/phone"
import { Lang } from "@scandic-hotels/common/constants/language"
export enum Lang {
da = "da",
de = "de",
en = "en",
fi = "fi",
no = "no",
sv = "sv",
}
import type { LowerCaseCountryCode } from "@/types/components/form/phone"
export const languages: Record<Lang, string> = {
[Lang.da]: "Dansk",

View File

@@ -1,5 +1,5 @@
/**
* @typedef {import('@/constants/languages').Lang} Lang
* @typedef {import('@scandic-hotels/common/constants/language').Lang} Lang
*/
/**

View File

@@ -1,4 +1,4 @@
import { Lang } from "./languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import type { LangRoute } from "@/types/routes"

View File

@@ -4,7 +4,7 @@ import { z } from "zod"
import { getLiveStatus } from "./getLiveStatus"
import { isLangLive } from "./isLangLive"
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
const _env = createEnv({
client: {

View File

@@ -1,5 +1,4 @@
// Cannot use from "@/constants/languages" due to jiti
import { Lang } from "../constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
export function getLiveStatus(
internalEnv:

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from "@jest/globals"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { isLangLive } from "./isLangLive"

View File

@@ -1,4 +1,4 @@
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
export function isLangLive(lang: Lang, liveLangs: string[]): boolean {
return liveLangs.includes(lang)

View File

@@ -4,7 +4,7 @@ import { z } from "zod"
import { getLiveStatus } from "./getLiveStatus"
import { isLangLive } from "./isLangLive"
import type { Lang } from "../constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
const TWENTYFOUR_HOURS = 24 * 60 * 60

View File

@@ -1,7 +1,7 @@
"use client"
import { useParams } from "next/navigation"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { languageSchema } from "@/utils/languages"

View File

@@ -2,7 +2,7 @@ import "server-only"
import { createIntl, createIntlCache } from "@formatjs/intl"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { getLang } from "@/i18n/serverContext"

View File

@@ -3,7 +3,7 @@ import "server-only"
import { headers } from "next/headers"
import { cache } from "react"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { languageSchema } from "@/utils/languages"

View File

@@ -2,7 +2,8 @@ import "server-only"
import { ClientError, type GraphQLClient } from "graphql-request"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { env } from "@/env/server"
import type { DocumentNode } from "graphql"

View File

@@ -8,10 +8,11 @@ import {
import { httpLink, loggerLink, TRPCClientError } from "@trpc/client"
import { useState } from "react"
import { SessionExpiredError } from "@scandic-hotels/trpc/errors"
import { transformer } from "@scandic-hotels/trpc/transformer"
import { login } from "@/constants/routes/handleAuth"
import { env } from "@/env/client"
import { SessionExpiredError } from "@/server/errors/trpc"
import { transformer } from "@/server/transformer"
import useLang from "@/hooks/useLang"

View File

@@ -7,6 +7,8 @@ import { cache } from "@/utils/cache"
import { serverClient } from "../server"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { Country } from "@/types/enums/country"
import type {
AncillaryPackagesInput,
@@ -18,7 +20,6 @@ import type {
CityCoordinatesInput,
HotelInput,
} from "@/types/trpc/routers/hotel/hotel"
import type { Lang } from "@/constants/languages"
import type { GetHotelsByCSFilterInput } from "@/server/routers/hotels/input"
import type { GetSavedPaymentCardsInput } from "@/server/routers/user/input"

View File

@@ -1,18 +1,57 @@
import * as Sentry from "@sentry/nextjs"
import { TRPCError } from "@trpc/server"
import { cookies, headers } from "next/headers"
import { redirect } from "next/navigation"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { createCallerFactory } from "@scandic-hotels/trpc"
import { createContext } from "@scandic-hotels/trpc/context"
import { login } from "@/constants/routes/handleAuth"
import { webviews } from "@/constants/routes/webviews"
import { appRouter } from "@/server"
import { createContext } from "@/server/context"
import { createCallerFactory } from "@/server/trpc"
import { auth } from "@/auth"
import type { Session } from "next-auth"
const createCaller = createCallerFactory(appRouter)
export async function createAppContext() {
const headersList = await headers()
const cookie = await cookies()
const webviewTokenCookie = cookie.get("webviewToken")
const loginType = headersList.get("loginType")
const ctx = createContext({
lang: headersList.get("x-lang") as Lang,
pathname: headersList.get("x-pathname")!,
uid: headersList.get("x-uid"),
url: headersList.get("x-url")!,
webToken: webviewTokenCookie?.value,
contentType: headersList.get("x-contenttype")!,
auth: async () => {
const session = await auth()
const webToken = webviewTokenCookie?.value
if (!session?.token && !webToken) {
return null
}
return (
session ||
({
token: { access_token: webToken, loginType },
} as Session)
)
},
})
return ctx
}
export async function serverClient() {
const ctx = await createContext()
const ctx = await createAppContext()
return createCaller(ctx, {
onError: ({ ctx, error, input, path, type }) => {
console.error(`[serverClient] error for ${type}: ${path}`, error)

View File

@@ -1,7 +1,7 @@
import * as Sentry from "@sentry/nextjs"
import { type NextMiddleware, NextResponse } from "next/server"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import * as authRequired from "@/middlewares/authRequired"
import * as bookingFlow from "@/middlewares/bookingFlow"

View File

@@ -9,8 +9,9 @@ import { findLang } from "@/utils/languages"
import { getDefaultRequestHeaders } from "./utils"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { MiddlewareMatcher } from "@/types/middleware"
import type { Lang } from "@/constants/languages"
async function fetchAndCacheRedirect(lang: Lang, pathname: string) {
const cacheKey = `${lang}:redirect:${pathname}`

View File

@@ -1,6 +1,6 @@
import { type NextMiddleware, NextResponse } from "next/server"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { getDefaultRequestHeaders } from "./utils"

View File

@@ -16,8 +16,9 @@ import { findLang } from "@/utils/languages"
import { getDefaultRequestHeaders } from "./utils"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { MiddlewareMatcher } from "@/types/middleware"
import type { Lang } from "@/constants/languages"
export const middleware: NextMiddleware = async (request) => {
const { nextUrl } = request

View File

@@ -1,4 +1,4 @@
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
export async function warmupHotelDataOnLang(lang: Lang) {
const PUBLIC_URL = Netlify.env.get("PUBLIC_URL")

View File

@@ -25,7 +25,7 @@ const nextConfig = {
poweredByHeader: false,
eslint: { ignoreDuringBuilds: true },
trailingSlash: false,
transpilePackages: ["@scandic-hotels/common"],
transpilePackages: ["@scandic-hotels/common", "@scandic-hotels/trpc"],
experimental: {
serverActions: {
allowedOrigins: [

View File

@@ -109,7 +109,6 @@
"slugify": "^1.6.6",
"sonner": "^2.0.3",
"supercluster": "^8.0.1",
"superjson": "^2.2.2",
"usehooks-ts": "3.1.1",
"uuid": "^11.1.0",
"zod": "^3.24.4",

View File

@@ -9,6 +9,8 @@ import { createMyStayStore } from "@/stores/my-stay"
import { MyStaySkeleton } from "@/components/HotelReservation/MyStay/myStaySkeleton"
import { MyStayContext } from "@/contexts/MyStay"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { Packages } from "@/types/components/myPages/myStay/ancillaries"
import type { MyStayStore } from "@/types/contexts/my-stay"
import type { RoomCategories } from "@/types/hotel"
@@ -17,7 +19,6 @@ import type {
BookingConfirmationSchema,
} from "@/types/trpc/routers/booking/confirmation"
import type { CreditCard } from "@/types/user"
import type { Lang } from "@/constants/languages"
interface MyStayProviderProps {
bookingConfirmation: BookingConfirmation

View File

@@ -1,72 +0,0 @@
import { cookies, headers } from "next/headers"
import { type Session } from "next-auth"
import { cache } from "react"
import { auth } from "@/auth"
import type { Lang } from "@/constants/languages"
typeof auth
type CreateContextOptions = {
auth: () => Promise<Session | null>
lang: Lang
pathname: string
uid?: string | null
url: string
webToken?: string
contentType?: string
}
/** Use this helper for:
* - testing, where we dont have to Mock Next.js' req/res
* - trpc's `createSSGHelpers` where we don't have req/res
**/
export function createContextInner(opts: CreateContextOptions) {
return {
auth: opts.auth,
lang: opts.lang,
pathname: opts.pathname,
uid: opts.uid,
url: opts.url,
webToken: opts.webToken,
contentType: opts.contentType,
}
}
/**
* This is the actual context you'll use in your router
* @link https://trpc.io/docs/context
**/
export const createContext = cache(async function () {
const headersList = await headers()
const cookie = await cookies()
const webviewTokenCookie = cookie.get("webviewToken")
const loginType = headersList.get("loginType")
return createContextInner({
auth: async () => {
const session = await auth()
const webToken = webviewTokenCookie?.value
if (!session?.token && !webToken) {
return null
}
return (
session ||
({
token: { access_token: webToken, loginType },
} as Session)
)
},
lang: headersList.get("x-lang") as Lang,
pathname: headersList.get("x-pathname")!,
uid: headersList.get("x-uid"),
url: headersList.get("x-url")!,
webToken: webviewTokenCookie?.value,
contentType: headersList.get("x-contenttype")!,
})
})
export type Context = Awaited<ReturnType<typeof createContext>>

View File

@@ -1,4 +1,6 @@
/** Routers */
import { router } from "@scandic-hotels/trpc"
import { autocompleteRouter } from "./routers/autocomplete"
import { bookingRouter } from "./routers/booking"
import { contentstackRouter } from "./routers/contentstack"
@@ -6,7 +8,6 @@ import { hotelsRouter } from "./routers/hotels"
import { navigationRouter } from "./routers/navigation"
import { partnerRouter } from "./routers/partners"
import { userRouter } from "./routers/user"
import { router } from "./trpc"
export const appRouter = router({
booking: bookingRouter,

View File

@@ -3,8 +3,8 @@ import { z } from "zod"
import { parseRefId } from "@/utils/refId"
import type { Meta } from "@/types/trpc/meta"
import type { Context } from "../context"
import type { Meta } from "@scandic-hotels/trpc"
import type { Context } from "@scandic-hotels/trpc/context"
export function createRefIdPlugin() {
const t = initTRPC.context<Context>().meta<Meta>().create()

View File

@@ -1,10 +1,10 @@
import { z } from "zod"
import { Lang } from "@scandic-hotels/common/constants/language"
import { getCacheClient } from "@scandic-hotels/common/dataCache"
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
import { safeProtectedServiceProcedure } from "@scandic-hotels/trpc/procedures"
import { Lang } from "@/constants/languages"
import { safeProtectedServiceProcedure } from "@/server/trpc"
import { isDefined } from "@/server/utils"
import { getCityPageUrls } from "../contentstack/destinationCityPage/utils"

View File

@@ -1,4 +1,4 @@
import { router } from "@/server/trpc"
import { router } from "@scandic-hotels/trpc"
import { getDestinationsAutoCompleteRoute } from "./destinations"

View File

@@ -1,4 +1,4 @@
import { mergeRouters } from "@/server/trpc"
import { mergeRouters } from "@scandic-hotels/trpc"
import { bookingMutationRouter } from "./mutation"
import { bookingQueryRouter } from "./query"

View File

@@ -1,7 +1,9 @@
import { z } from "zod"
import { Lang } from "@scandic-hotels/common/constants/language"
import { ChildBedTypeEnum } from "@/constants/booking"
import { Lang, langToApiLang } from "@/constants/languages"
import { langToApiLang } from "@/constants/languages"
const roomsSchema = z
.array(

View File

@@ -1,8 +1,10 @@
import { createCounter } from "@scandic-hotels/common/telemetry"
import { router } from "@scandic-hotels/trpc"
import { safeProtectedServiceProcedure } from "@scandic-hotels/trpc/procedures"
import * as api from "@/lib/api"
import { createRefIdPlugin } from "@/server/plugins/refIdToConfirmationNumber"
import { getMembershipNumber } from "@/server/routers/user/utils"
import { createCounter } from "@/server/telemetry"
import { router, safeProtectedServiceProcedure } from "@/server/trpc"
import { encrypt } from "@/utils/encryption"
import { isValidSession } from "@/utils/session"

View File

@@ -1,12 +1,16 @@
import * as api from "@/lib/api"
import { badRequestError, serverErrorByStatus } from "@/server/errors/trpc"
import { createRefIdPlugin } from "@/server/plugins/refIdToConfirmationNumber"
import { createCounter } from "@/server/telemetry"
import { createCounter } from "@scandic-hotels/common/telemetry"
import { router } from "@scandic-hotels/trpc"
import {
badRequestError,
serverErrorByStatus,
} from "@scandic-hotels/trpc/errors"
import {
router,
safeProtectedServiceProcedure,
serviceProcedure,
} from "@/server/trpc"
} from "@scandic-hotels/trpc/procedures"
import * as api from "@/lib/api"
import { createRefIdPlugin } from "@/server/plugins/refIdToConfirmationNumber"
import { toApiLang } from "@/server/utils"
import { getBookedHotelRoom } from "@/utils/booking"

View File

@@ -1,11 +1,15 @@
import { createCounter } from "@scandic-hotels/common/telemetry"
import {
badRequestError,
serverErrorByStatus,
} from "@scandic-hotels/trpc/errors"
import * as api from "@/lib/api"
import { badRequestError, serverErrorByStatus } from "@/server/errors/trpc"
import { createCounter } from "@/server/telemetry"
import { toApiLang } from "@/server/utils"
import { bookingConfirmationSchema, createBookingSchema } from "./output"
import type { Lang } from "@/constants/languages"
import type { Lang } from "@scandic-hotels/common/constants/language"
export async function getBooking(
confirmationNumber: string,

View File

@@ -1,4 +1,4 @@
import { mergeRouters } from "@/server/trpc"
import { mergeRouters } from "@scandic-hotels/trpc"
import { accountPageQueryRouter } from "./query"

View File

@@ -1,11 +1,13 @@
import { createCounter } from "@scandic-hotels/common/telemetry"
import { router } from "@scandic-hotels/trpc"
import { notFound } from "@scandic-hotels/trpc/errors"
import { contentstackExtendedProcedureUID } from "@scandic-hotels/trpc/procedures"
import {
GetAccountPage,
GetAccountPageRefs,
} from "@/lib/graphql/Query/AccountPage/AccountPage.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { createCounter } from "@/server/telemetry"
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
import {
generateRefsResponseTag,

View File

@@ -1,4 +1,4 @@
import { mergeRouters } from "@/server/trpc"
import { mergeRouters } from "@scandic-hotels/trpc"
import { baseQueryRouter } from "./query"

View File

@@ -1,6 +1,7 @@
import { z, ZodError, ZodIssueCode } from "zod"
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { discriminatedUnion } from "@/lib/discriminatedUnion"
import {
cardBlockRefsSchema,

View File

@@ -1,5 +1,10 @@
import { cache } from "react"
import { createCounter } from "@scandic-hotels/common/telemetry"
import { router } from "@scandic-hotels/trpc"
import { notFound } from "@scandic-hotels/trpc/errors"
import { contentstackBaseProcedure } from "@scandic-hotels/trpc/procedures"
import { GetContactConfig } from "@/lib/graphql/Query/ContactConfig.graphql"
import {
GetCurrentFooter,
@@ -16,9 +21,6 @@ import {
GetSiteConfigRef,
} from "@/lib/graphql/Query/SiteConfig.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { createCounter } from "@/server/telemetry"
import { contentstackBaseProcedure, router } from "@/server/trpc"
import { langInput } from "@/server/utils"
import {
@@ -51,6 +53,8 @@ import {
getSiteConfigConnections,
} from "./utils"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type {
FooterDataRaw,
FooterRefDataRaw,
@@ -63,7 +67,6 @@ import type {
GetSiteConfigData,
GetSiteConfigRefData,
} from "@/types/trpc/routers/contentstack/siteConfig"
import type { Lang } from "@/constants/languages"
const getContactConfig = cache(async (lang: Lang) => {
const getContactConfigCounter = createCounter(

View File

@@ -1,4 +1,4 @@
import { mergeRouters } from "@/server/trpc"
import { mergeRouters } from "@scandic-hotels/trpc"
import { breadcrumbsQueryRouter } from "./query"

View File

@@ -1,5 +1,10 @@
import { cache } from "react"
import { createCounter } from "@scandic-hotels/common/telemetry"
import { router } from "@scandic-hotels/trpc"
import { notFound } from "@scandic-hotels/trpc/errors"
import { contentstackExtendedProcedureUID } from "@scandic-hotels/trpc/procedures"
import {
GetMyPagesBreadcrumbs,
GetMyPagesBreadcrumbsRefs,
@@ -37,21 +42,19 @@ import {
GetLoyaltyPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/LoyaltyPage.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { createCounter } from "@/server/telemetry"
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
import { generateRefsResponseTag } from "@/utils/generateTag"
import { breadcrumbsRefsSchema, breadcrumbsSchema } from "./output"
import { getTags } from "./utils"
import type { Lang } from "@scandic-hotels/common/constants/language"
import { PageContentTypeEnum } from "@/types/requests/contentType"
import type {
BreadcrumbsRefsSchema,
RawBreadcrumbsSchema,
} from "@/types/trpc/routers/contentstack/breadcrumbs"
import type { Lang } from "@/constants/languages"
interface BreadcrumbsPageData<T> {
dataKey: keyof T

View File

@@ -1,4 +1,4 @@
import { Lang } from "@/constants/languages"
import { Lang } from "@scandic-hotels/common/constants/language"
import { generateTag, generateTags } from "@/utils/generateTag"

View File

@@ -1,4 +1,4 @@
import { mergeRouters } from "@/server/trpc"
import { mergeRouters } from "@scandic-hotels/trpc"
import { campaignPageQueryRouter } from "./query"

View File

@@ -1,11 +1,13 @@
import { createCounter } from "@scandic-hotels/common/telemetry"
import { router } from "@scandic-hotels/trpc"
import { notFound } from "@scandic-hotels/trpc/errors"
import { contentStackUidWithServiceProcedure } from "@scandic-hotels/trpc/procedures"
import {
GetCampaignPage,
GetCampaignPageRefs,
} from "@/lib/graphql/Query/CampaignPage/CampaignPage.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { createCounter } from "@/server/telemetry"
import { contentStackUidWithServiceProcedure, router } from "@/server/trpc"
import { generateRefsResponseTag } from "@/utils/generateTag"

View File

@@ -1,9 +1,10 @@
import { generateTag, generateTagsFromSystem } from "@/utils/generateTag"
import type { Lang } from "@scandic-hotels/common/constants/language"
import { CampaignPageEnum } from "@/types/enums/campaignPage"
import type { System } from "@/types/requests/system"
import type { CampaignPageRefs } from "@/types/trpc/routers/contentstack/campaignPage"
import type { Lang } from "@/constants/languages"
export function generatePageTags(
validatedData: CampaignPageRefs,

View File

@@ -1,4 +1,4 @@
import { mergeRouters } from "@/server/trpc"
import { mergeRouters } from "@scandic-hotels/trpc"
import { collectionPageQueryRouter } from "./query"

View File

@@ -1,7 +1,9 @@
import { createCounter } from "@scandic-hotels/common/telemetry"
import { router } from "@scandic-hotels/trpc"
import { contentstackExtendedProcedureUID } from "@scandic-hotels/trpc/procedures"
import { GetCollectionPage } from "@/lib/graphql/Query/CollectionPage/CollectionPage.graphql"
import { request } from "@/lib/graphql/request"
import { createCounter } from "@/server/telemetry"
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
import { collectionPageSchema } from "./output"
import {

View File

@@ -1,7 +1,8 @@
import { createCounter } from "@scandic-hotels/common/telemetry"
import { notFound } from "@scandic-hotels/trpc/errors"
import { GetCollectionPageRefs } from "@/lib/graphql/Query/CollectionPage/CollectionPage.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { createCounter } from "@/server/telemetry"
import {
generateRefsResponseTag,
@@ -11,13 +12,14 @@ import {
import { collectionPageRefsSchema } from "./output"
import type { Lang } from "@scandic-hotels/common/constants/language"
import { CollectionPageEnum } from "@/types/enums/collectionPage"
import type { System } from "@/types/requests/system"
import type {
CollectionPageRefs,
GetCollectionPageRefsSchema,
} from "@/types/trpc/routers/contentstack/collectionPage"
import type { Lang } from "@/constants/languages"
export async function fetchCollectionPageRefs(lang: Lang, uid: string) {
const getCollectionPageRefsCounter = createCounter(

Some files were not shown because too many files have changed in this diff Show More