From 46ebbbba8f73a8c53fbfd95c2d88de2c12394f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20J=C3=A4derberg?= Date: Wed, 5 Feb 2025 14:43:14 +0000 Subject: [PATCH] Merged in feature/sas-login (pull request #1256) First steps towards the SAS partnership * otp flow now pretends to do the linking * Update LinkAccountForm header * Update redirect times * Clean up comments * Set maxAge on sas cookies * make all SAS routes protected * Merge remote-tracking branch 'refs/remotes/origin/feature/sas-login' into feature/sas-login * Require auth for sas link flow * Fix resend otp * Add error support to OneTimePasswordForm * Add Sentry to SAS error boundary * Move SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME * Add missing translations * Merge branch 'master' of bitbucket.org:scandic-swap/web into feature/sas-login * Merge branch 'feature/sas-login' of bitbucket.org:scandic-swap/web into feature/sas-login * Add TooManyCodesError component * Refactor GenericError to support new errors * Add FailedAttemptsError * remove removed component * Merge branch 'feature/sas-login' of bitbucket.org:scandic-swap/web into feature/sas-login * remove local cookie-bot reference * Fix sas campaign logo scaling * feature toggle the SAS stuff * Merge branch 'feature/sas-login' of bitbucket.org:scandic-swap/web into feature/sas-login * fix: use env vars for SAS endpoints Approved-by: Linus Flood --- app/[lang]/(live)/(protected)/layout.tsx | 72 +--- .../(partner)/(sas)/(protected)/layout.tsx | 3 + .../sas-x-scandic/callback/route.ts | 105 ++++++ .../components/AlreadyLinkedError.tsx | 35 ++ .../components/DateOfBirthError.tsx | 34 ++ .../components/FailedAttemptsError.tsx | 28 ++ .../sas-x-scandic/components/GenericError.tsx | 39 +++ .../components/SASModal.module.css | 45 +++ .../sas-x-scandic/components/SASModal.tsx | 53 +++ .../components/TooManyCodesError.tsx | 28 ++ .../(sas)/(protected)/sas-x-scandic/error.tsx | 40 +++ .../(protected)/sas-x-scandic/error/page.tsx | 34 ++ .../sas-x-scandic/layout.module.css | 53 +++ .../(protected)/sas-x-scandic/layout.tsx | 63 ++++ .../sas-x-scandic/link/LinkAccountForm.tsx | 136 ++++++++ .../sas-x-scandic/link/link-sas.module.css | 43 +++ .../(protected)/sas-x-scandic/link/page.tsx | 41 +++ .../sas-x-scandic/link/success/page.tsx | 41 +++ .../(protected)/sas-x-scandic/login/page.tsx | 90 +++++ .../otp/OneTimePasswordForm.module.css | 92 +++++ .../sas-x-scandic/otp/OneTimePasswordForm.tsx | 198 +++++++++++ .../(protected)/sas-x-scandic/otp/loading.tsx | 11 + .../(protected)/sas-x-scandic/otp/page.tsx | 128 +++++++ .../(protected)/sas-x-scandic/sasUtils.ts | 9 + app/[lang]/(partner)/layout.tsx | 68 ++++ app/api/debug/route.ts | 16 + .../Details/MemberPriceModal/modal.module.css | 2 +- components/Icons/ErrorCircleFilled.tsx | 27 ++ components/ProtectedLayout.tsx | 69 ++++ components/Redirect.tsx | 19 ++ env/server.ts | 19 ++ i18n/dictionaries/da.json | 24 ++ i18n/dictionaries/de.json | 24 ++ i18n/dictionaries/en.json | 27 ++ i18n/dictionaries/fi.json | 24 ++ i18n/dictionaries/no.json | 24 ++ i18n/dictionaries/sv.json | 24 ++ middleware.ts | 2 + middlewares/sasXScandic.ts | 22 ++ package-lock.json | 69 +++- package.json | 3 + .../img/partner/sas/sas-campaign-logo.png | Bin 0 -> 11015 bytes ...s_x_scandic_airplane_window_background.jpg | Bin 0 -> 163407 bytes public/_static/img/scandic-loyalty-time.svg | 323 ++++++++++++++++++ server/context.ts | 4 +- server/index.ts | 2 + server/routers/contentstack/reward/utils.ts | 9 +- server/routers/partners/index.ts | 5 + server/routers/partners/sas/getSasToken.ts | 11 + server/routers/partners/sas/index.ts | 7 + server/routers/partners/sas/linkAccount.ts | 28 ++ server/routers/partners/sas/otp/constants.ts | 2 + .../routers/partners/sas/otp/getOTPState.ts | 17 + .../partners/sas/otp/request/requestOtp.ts | 116 +++++++ .../sas/otp/request/requestOtpError.test.ts | 37 ++ .../sas/otp/request/requestOtpError.ts | 61 ++++ .../partners/sas/otp/verify/verifyOtp.ts | 96 ++++++ .../sas/otp/verify/verifyOtpError.test.ts | 24 ++ .../partners/sas/otp/verify/verifyOtpError.ts | 57 ++++ server/trpc.ts | 4 + types/components/hotelLogo.ts | 2 +- .../selectHotel/hotelCardProps.ts | 6 +- 62 files changed, 2606 insertions(+), 89 deletions(-) create mode 100644 app/[lang]/(partner)/(sas)/(protected)/layout.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/AlreadyLinkedError.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/DateOfBirthError.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/FailedAttemptsError.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/GenericError.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/SASModal.module.css create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/SASModal.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/TooManyCodesError.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error/page.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.module.css create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/LinkAccountForm.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/link-sas.module.css create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/page.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/success/page.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/login/page.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/OneTimePasswordForm.module.css create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/OneTimePasswordForm.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/loading.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx create mode 100644 app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/sasUtils.ts create mode 100644 app/[lang]/(partner)/layout.tsx create mode 100644 app/api/debug/route.ts create mode 100644 components/Icons/ErrorCircleFilled.tsx create mode 100644 components/ProtectedLayout.tsx create mode 100644 components/Redirect.tsx create mode 100644 middlewares/sasXScandic.ts create mode 100644 public/_static/img/partner/sas/sas-campaign-logo.png create mode 100644 public/_static/img/partner/sas/sas_x_scandic_airplane_window_background.jpg create mode 100644 public/_static/img/scandic-loyalty-time.svg create mode 100644 server/routers/partners/index.ts create mode 100644 server/routers/partners/sas/getSasToken.ts create mode 100644 server/routers/partners/sas/index.ts create mode 100644 server/routers/partners/sas/linkAccount.ts create mode 100644 server/routers/partners/sas/otp/constants.ts create mode 100644 server/routers/partners/sas/otp/getOTPState.ts create mode 100644 server/routers/partners/sas/otp/request/requestOtp.ts create mode 100644 server/routers/partners/sas/otp/request/requestOtpError.test.ts create mode 100644 server/routers/partners/sas/otp/request/requestOtpError.ts create mode 100644 server/routers/partners/sas/otp/verify/verifyOtp.ts create mode 100644 server/routers/partners/sas/otp/verify/verifyOtpError.test.ts create mode 100644 server/routers/partners/sas/otp/verify/verifyOtpError.ts diff --git a/app/[lang]/(live)/(protected)/layout.tsx b/app/[lang]/(live)/(protected)/layout.tsx index 45237ee30..3abbbf920 100644 --- a/app/[lang]/(live)/(protected)/layout.tsx +++ b/app/[lang]/(live)/(protected)/layout.tsx @@ -1,71 +1,3 @@ -import { headers } from "next/headers" -import { redirect } from "next/navigation" +import { ProtectedLayout } from "@/components/ProtectedLayout" -import { overview } from "@/constants/routes/myPages" -import { getProfile } from "@/lib/trpc/memoizedRequests" - -import { auth } from "@/auth" -import { getIntl } from "@/i18n" -import { getLang } from "@/i18n/serverContext" - -export default async function ProtectedLayout({ - children, -}: React.PropsWithChildren) { - const intl = await getIntl() - const session = await auth() - /** - * Fallback to make sure every route nested in the - * protected route group is actually protected. - */ - const h = headers() - const redirectTo = encodeURIComponent( - h.get("x-url") ?? h.get("x-pathname") ?? overview[getLang()] - ) - - const redirectURL = `/${getLang()}/login?redirectTo=${redirectTo}` - - if (!session) { - console.log(`[layout:protected] no session, redirecting to: ${redirectURL}`) - redirect(redirectURL) - } - - const user = await getProfile() - - if (user && "error" in user) { - // redirect(redirectURL) - console.error("[layout:protected] error in user", user) - console.error( - "[layout:protected] full user: ", - JSON.stringify(user, null, 4) - ) - switch (user.cause) { - case "unauthorized": // fall through - case "forbidden": // fall through - case "token_expired": - console.error( - `[layout:protected] user error, redirecting to: ${redirectURL}` - ) - redirect(redirectURL) - case "notfound": - console.error(`[layout:protected] notfound user loading error`) - break - case "unknown": - console.error(`[layout:protected] unknown user loading error`) - break - default: - console.error(`[layout:protected] unhandled user loading error`) - break - } - return

{intl.formatMessage({ id: "Something went wrong!" })}

- } - - if (!user) { - console.error( - "[layout:protected] no user found, redirecting to: ", - redirectURL - ) - redirect(redirectURL) - } - - return children -} +export default ProtectedLayout diff --git a/app/[lang]/(partner)/(sas)/(protected)/layout.tsx b/app/[lang]/(partner)/(sas)/(protected)/layout.tsx new file mode 100644 index 000000000..3abbbf920 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/layout.tsx @@ -0,0 +1,3 @@ +import { ProtectedLayout } from "@/components/ProtectedLayout" + +export default ProtectedLayout diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts new file mode 100644 index 000000000..931b5dbad --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts @@ -0,0 +1,105 @@ +import { cookies } from "next/headers" +import { redirect } from "next/navigation" +import { z } from "zod" + +import { env } from "@/env/server" +import { serverClient } from "@/lib/trpc/server" + +import { safeTry } from "@/utils/safeTry" + +import { SAS_TOKEN_STORAGE_KEY, stateSchema } from "../sasUtils" + +import type { NextRequest } from "next/server" + +const searchParamsSchema = z.object({ + code: z.string(), + state: z.string(), +}) +const tokenResponseSchema = z.object({ + access_token: z.string(), + expires_in: z.number(), + token_type: z.literal("Bearer"), +}) + +export async function GET( + request: NextRequest, + { params }: { params: { lang: string } } +) { + const { lang } = params + + const result = searchParamsSchema.safeParse({ + code: request.nextUrl.searchParams.get("code"), + state: request.nextUrl.searchParams.get("state"), + }) + + if (!result.success) { + console.error("[SAS] Invalid search params", result.error) + redirect(`/${lang}/sas-x-scandic/error?errorCode=invalid_query`) + } + const { code, state } = result.data + + const tokenResponse = await fetch( + new URL("oauth/token", env.SAS_AUTH_ENDPOINT), + { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: new URLSearchParams({ + grant_type: "authorization_code", + code: code, + redirect_uri: new URL( + `/${lang}/sas-x-scandic/callback`, + new URL(env.PUBLIC_URL) + ).toString(), + client_id: env.SAS_AUTH_CLIENTID, + }), + } + ) + + if (!tokenResponse.ok) { + const error = await tokenResponse.text() + console.error("[SAS] Failed to get token", error) + redirect(`/${lang}/sas-x-scandic/error?errorCode=token_error`) + } + + const tokenData = tokenResponseSchema.parse(await tokenResponse.json()) + + const stateResult = stateSchema.safeParse( + JSON.parse(decodeURIComponent(state)) + ) + if (!stateResult.success) { + redirect(`/${lang}/sas-x-scandic/error?errorCode=invalid_state`) + } + + const cookieStore = cookies() + cookieStore.set(SAS_TOKEN_STORAGE_KEY, tokenData.access_token, { + maxAge: 3600, + httpOnly: true, + }) + + if (stateResult.data.intent === "link") { + const [data, error] = await safeTry( + serverClient().partner.sas.requestOtp({}) + ) + // status: 'SENT' => OK + if (!data || error) { + //TODO: Check what error we get + console.error("[SAS] Failed to request OTP", error) + redirect(`/${lang}/sas-x-scandic/error`) + } + + console.log("[SAS] Request OTP response", data) + + const otpUrl = new URL( + `/${lang}/sas-x-scandic/otp`, + new URL(env.PUBLIC_URL) + ) + otpUrl.searchParams.set("intent", stateResult.data.intent) + otpUrl.searchParams.set("to", data.otpReceiver) + + redirect(otpUrl.toString()) + } + + redirect(`/${lang}/sas-x-scandic/error?errorCode=unknown_intent`) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/AlreadyLinkedError.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/AlreadyLinkedError.tsx new file mode 100644 index 000000000..d50dcddd8 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/AlreadyLinkedError.tsx @@ -0,0 +1,35 @@ +"use client" +import Link from "next/link" +import { useIntl } from "react-intl" + +import ErrorCircleFilledIcon from "@/components/Icons/ErrorCircleFilled" +import Button from "@/components/TempDesignSystem/Button" +import Body from "@/components/TempDesignSystem/Text/Body" +import Title from "@/components/TempDesignSystem/Text/Title" + +import { SASModal, SASModalContactBlock, SASModalDivider } from "./SASModal" + +export function AlreadyLinkedError() { + const intl = useIntl() + + return ( + + + + {intl.formatMessage({ id: "Accounts are already linked" })} + + + {/* TODO copy */} + {intl.formatMessage({ + id: "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.", + })} + + {/* TODO link to SASxScandic page on My Pages */} + + + + + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/DateOfBirthError.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/DateOfBirthError.tsx new file mode 100644 index 000000000..35c789e8c --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/DateOfBirthError.tsx @@ -0,0 +1,34 @@ +"use client" +import { useIntl } from "react-intl" + +import ErrorCircleFilledIcon from "@/components/Icons/ErrorCircleFilled" +import Button from "@/components/TempDesignSystem/Button" +import Body from "@/components/TempDesignSystem/Text/Body" +import Title from "@/components/TempDesignSystem/Text/Title" + +import { SASModal, SASModalContactBlock, SASModalDivider } from "./SASModal" + +export function DateOfBirthError() { + const intl = useIntl() + + return ( + + + + {intl.formatMessage({ id: "Date of birth not matching" })} + + + {/* TODO copy */} + {intl.formatMessage({ + id: "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.", + })} + + {/* TODO link to where? */} + + + + + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/FailedAttemptsError.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/FailedAttemptsError.tsx new file mode 100644 index 000000000..6da0ec424 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/FailedAttemptsError.tsx @@ -0,0 +1,28 @@ +"use client" + +import { useIntl } from "react-intl" + +import Button from "@/components/TempDesignSystem/Button" +import Body from "@/components/TempDesignSystem/Text/Body" + +import { GenericError } from "./GenericError" + +export function FailedAttemptsError() { + const intl = useIntl() + + return ( + + + {intl.formatMessage({ + id: "Please wait 1 hour before trying again.", + })} + + + + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/GenericError.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/GenericError.tsx new file mode 100644 index 000000000..c8216dfec --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/GenericError.tsx @@ -0,0 +1,39 @@ +"use client" +import Image from "next/image" + +import ErrorCircleFilledIcon from "@/components/Icons/ErrorCircleFilled" +import Title from "@/components/TempDesignSystem/Text/Title" + +import { SASModal } from "./SASModal" + +import type { ReactNode } from "react" + +export function GenericError({ + title, + variant = "error", + children, +}: { + title: ReactNode + variant?: "error" | "info" + children: ReactNode +}) { + return ( + + {variant === "error" ? ( + + ) : ( + + )} + + {title} + + {children} + + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/SASModal.module.css b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/SASModal.module.css new file mode 100644 index 000000000..1859d4279 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/SASModal.module.css @@ -0,0 +1,45 @@ +.container { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--Spacing-x3); + background-color: white; + width: 100%; + padding: var(--Spacing-x3) var(--Spacing-x3) var(--Spacing-x4); + text-align: center; + border-radius: var(--Corner-radius-Medium) var(--Corner-radius-Medium) 0 0; + margin-top: auto; + + @media screen and (min-width: 768px) { + & { + border-radius: var(--Corner-radius-Medium); + margin-top: initial; + width: 560px; + } + } +} + +.divider { + width: 100%; + position: relative; + + & > span { + position: relative; + padding: 0 var(--Spacing-x2); + background-color: white; + } + + &::before { + position: absolute; + bottom: calc(50% - 1px); + content: ""; + display: block; + height: 1px; + width: 100%; + background-color: var(--Base-Border-Subtle); + } +} + +.contactBlockTitle { + margin-bottom: var(--Spacing-x1); +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/SASModal.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/SASModal.tsx new file mode 100644 index 000000000..26886ed2d --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/SASModal.tsx @@ -0,0 +1,53 @@ +"use client" + +import { useIntl } from "react-intl" + +import Link from "@/components/TempDesignSystem/Link" +import Body from "@/components/TempDesignSystem/Text/Body" +import Title from "@/components/TempDesignSystem/Text/Title" + +import styles from "./SASModal.module.css" + +export function SASModal({ children }: { children: React.ReactNode }) { + return
{children}
+} + +export function SASModalDivider() { + const intl = useIntl() + + return ( +
+ + {intl.formatMessage({ id: "or" })} + +
+ ) +} + +export function SASModalContactBlock() { + const intl = useIntl() + + const phone = intl.formatMessage({ id: "+46 8 517 517 00" }) + + return ( +
+ + {intl.formatMessage({ id: "Contact our memberservice" })} + + + {phone} + + + member@scandichotels.com + +
+ ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/TooManyCodesError.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/TooManyCodesError.tsx new file mode 100644 index 000000000..e4a9ea180 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/components/TooManyCodesError.tsx @@ -0,0 +1,28 @@ +"use client" + +import { useIntl } from "react-intl" + +import Button from "@/components/TempDesignSystem/Button" +import Body from "@/components/TempDesignSystem/Text/Body" + +import { GenericError } from "./GenericError" + +export function TooManyCodesError() { + const intl = useIntl() + + return ( + + + {intl.formatMessage({ + id: "Please wait 1 hour before trying again.", + })} + + + + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error.tsx new file mode 100644 index 000000000..7f1958aea --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error.tsx @@ -0,0 +1,40 @@ +"use client" + +import * as Sentry from "@sentry/nextjs" +import { useEffect } from "react" +import { useIntl } from "react-intl" + +import Body from "@/components/TempDesignSystem/Text/Body" + +import { GenericError } from "./components/GenericError" +import { SASModalContactBlock } from "./components/SASModal" + +export default function Error({ + error, +}: { + error: Error & { digest?: string } +}) { + const intl = useIntl() + + useEffect(() => { + if (!error) return + + console.error(error) + Sentry.captureException(error) + }, [error]) + + return ( + + + {intl.formatMessage({ + id: "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.", + })} + + + + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error/page.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error/page.tsx new file mode 100644 index 000000000..feee2d359 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error/page.tsx @@ -0,0 +1,34 @@ +import Body from "@/components/TempDesignSystem/Text/Body" +import { getIntl } from "@/i18n" + +import { DateOfBirthError } from "../components/DateOfBirthError" +import { GenericError } from "../components/GenericError" +import { SASModalContactBlock } from "../components/SASModal" + +import type { LangParams, PageArgs, SearchParams } from "@/types/params" + +export default async function Page({ + searchParams, + params, +}: PageArgs & SearchParams<{ errorCode?: "dateOfBirthMismatch" }>) { + const intl = await getIntl() + + if (searchParams.errorCode === "dateOfBirthMismatch") { + return + } + + return ( + + + {intl.formatMessage({ + id: "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.", + })} + + + + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.module.css b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.module.css new file mode 100644 index 000000000..9fcb465aa --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.module.css @@ -0,0 +1,53 @@ +.layout { + background-size: cover; + background-position: center; + height: 100vh; + + display: grid; + grid-template-rows: 80px 1fr; +} + +.header { + background: white; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + justify-content: center; + align-items: center; + padding: 0 var(--Spacing-x2); +} + +.content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.logo { + margin-left: auto; + margin-right: auto; +} + +.backLink { + align-items: center; + color: var(--Scandic-Brand-Burgundy); + display: flex; + font-size: var(--Spacing-x2); + gap: var(--Spacing-x1); + + .long { + display: none; + } +} + +@media screen and (min-width: 768px) { + .backLink { + .short { + display: none; + } + + .long { + display: block; + } + } +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.tsx new file mode 100644 index 000000000..483a949c1 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.tsx @@ -0,0 +1,63 @@ +import { ArrowLeft } from "react-feather" + +import { overview as profileOverview } from "@/constants/routes/myPages" + +import Image from "@/components/Image" +import { ProtectedLayout } from "@/components/ProtectedLayout" +import Link from "@/components/TempDesignSystem/Link" +import { getIntl } from "@/i18n" +import background from "@/public/_static/img/partner/sas/sas_x_scandic_airplane_window_background.jpg" + +import styles from "./layout.module.css" + +import type { PropsWithChildren } from "react" + +import type { LangParams, LayoutArgs } from "@/types/params" + +export default async function SasXScandicLayout({ + children, + params, +}: PropsWithChildren>) { + const intl = await getIntl() + + return ( +
+
+ {/* TODO should this link to my-pages sas page? */} + + + + {intl.formatMessage({ id: "Back to Scandichotels.com" })} + + + {intl.formatMessage({ id: "Back" })} + + + +
+
{children}
+
+ ) +} + +async function MainMenuLogo() { + const intl = await getIntl() + + return +} + +function Logo({ alt }: { alt: string }) { + return ( + {alt} + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/LinkAccountForm.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/LinkAccountForm.tsx new file mode 100644 index 000000000..d54feeeba --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/LinkAccountForm.tsx @@ -0,0 +1,136 @@ +"use client" + +import Image from "next/image" +import { type ReactNode, useTransition } from "react" +import { FormProvider, useForm } from "react-hook-form" +import { useIntl } from "react-intl" + +import Button from "@/components/TempDesignSystem/Button" +import Checkbox from "@/components/TempDesignSystem/Form/Checkbox" +import DateSelect from "@/components/TempDesignSystem/Form/Date" +import Link from "@/components/TempDesignSystem/Link" +import Body from "@/components/TempDesignSystem/Text/Body" +import Caption from "@/components/TempDesignSystem/Text/Caption" +import Title from "@/components/TempDesignSystem/Text/Title" + +import styles from "./link-sas.module.css" + +type LinkAccountForm = { + dateOfBirth: string | null + termsAndConditions: boolean +} +export function LinkAccountForm({ + initialDateOfBirth, + onSubmit, +}: { + initialDateOfBirth: string | null + onSubmit: (dateOfBirth: string) => Promise +}) { + let [isPending, startTransition] = useTransition() + const intl = useIntl() + const form = useForm({ + defaultValues: { + dateOfBirth: initialDateOfBirth, + termsAndConditions: false, + }, + }) + + const handleSubmit = form.handleSubmit((data) => { + startTransition(async () => { + if (!data.dateOfBirth || !data.termsAndConditions) return + + await onSubmit(data.dateOfBirth) + }) + }) + + const dateOfBirth = form.watch("dateOfBirth") + const termsAndConditions = form.watch("termsAndConditions") + const disableSubmit = !dateOfBirth || !termsAndConditions + + return ( + +
+
+ {"Scandic + + {intl.formatMessage({ id: "Link your accounts" })} + +
+
+ + {intl.formatMessage({ + id: "Birth date", + })} + + +
+ + {intl.formatMessage({ + id: "We require this additional information in order to match your Scandic account with your EuroBonus account.", + })} + +
+ + + {intl.formatMessage({ id: "I accept the terms and conditions" })} + + + + {intl.formatMessage( + { + id: "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.", + }, + { + sasScandicTermsAndConditionsLink: (str) => ( + + {str} + + ), + } + )} + +
+
+ +
+
+
+ ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/link-sas.module.css b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/link-sas.module.css new file mode 100644 index 000000000..2e4cd2bd9 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/link-sas.module.css @@ -0,0 +1,43 @@ +.titles { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--Spacing-x2); + margin-top: var(--Spacing-x3); +} + +.dateSelect { + display: flex; + flex-direction: column; + gap: var(--Spacing-x1); + width: 100%; +} + +.termsAndConditions { + display: flex; + flex-direction: column; + gap: var(--Spacing-x2); +} + +.termsDescription { + margin-left: calc(var(--Spacing-x4) + var(--Spacing-x-half)); +} + +.ctaContainer { + display: flex; + justify-content: center; + padding: var(--Spacing-x3) var(--Spacing-x3) 0; + width: calc(100% + var(--Spacing-x3) + var(--Spacing-x3)); + border-top: 1px solid var(--Base-Border-Subtle); +} + +.ctaButton { + max-width: 350px; +} + +.form { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--Spacing-x3); +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/page.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/page.tsx new file mode 100644 index 000000000..171f8e4d2 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/page.tsx @@ -0,0 +1,41 @@ +import { redirect } from "next/navigation" +import React from "react" + +import { getProfileSafely } from "@/lib/trpc/memoizedRequests" + +import { AlreadyLinkedError } from "../components/AlreadyLinkedError" +import { SASModal } from "../components/SASModal" +import { LinkAccountForm } from "./LinkAccountForm" + +import type { LangParams, PageArgs } from "@/types/params" + +export default async function SASxScandicLinkPage({ + params, +}: PageArgs) { + const profile = await getProfileSafely() + + // TODO actually check if profile is already linked + const alreadyLinked = false + + async function handleLinkAccount(dateOfBirth: string) { + "use server" + + if (dateOfBirth !== profile?.dateOfBirth) { + // TODO update users date of birth here + console.log("updating date of birth") + } + + redirect(`/${params.lang}/sas-x-scandic/login?intent=link`) + } + + return alreadyLinked ? ( + + ) : ( + + + + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/success/page.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/success/page.tsx new file mode 100644 index 000000000..1398c0687 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/success/page.tsx @@ -0,0 +1,41 @@ +import React from "react" + +import CheckCircle from "@/components/Icons/CheckCircle" +import Body from "@/components/TempDesignSystem/Text/Body" +import Title from "@/components/TempDesignSystem/Text/Title" +import { getIntl } from "@/i18n" + +import { SASModal } from "../../components/SASModal" + +import type { LangParams, PageArgs } from "@/types/params" + +export default async function SASxScandicLinkPage({ + params, +}: PageArgs) { + const intl = await getIntl() + + return ( + + {/* */} + + + {intl.formatMessage({ id: "Your accounts are connected" })} + +
+ + {intl.formatMessage({ + id: "We successfully connected your accounts!", + })} + + + {intl.formatMessage({ + id: "Redirecting you to my pages.", + })} + +
+
+ ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/login/page.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/login/page.tsx new file mode 100644 index 000000000..542be9def --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/login/page.tsx @@ -0,0 +1,90 @@ +import { redirect } from "next/navigation" +import React from "react" +import { z } from "zod" + +import { env } from "@/env/server" + +import Image from "@/components/Image" +import { Redirect } from "@/components/Redirect" +import Link from "@/components/TempDesignSystem/Link" +import Body from "@/components/TempDesignSystem/Text/Body" +import Footnote from "@/components/TempDesignSystem/Text/Footnote" +import Title from "@/components/TempDesignSystem/Text/Title" +import { getIntl } from "@/i18n" + +import { SASModal } from "../components/SASModal" + +import type { LangParams, PageArgs, SearchParams } from "@/types/params" +import type { State } from "../sasUtils" + +const searchParamsSchema = z.object({ + intent: z.enum(["link"]), +}) +export default async function SASxScandicLoginPage({ + searchParams, + params, +}: PageArgs & SearchParams) { + const result = searchParamsSchema.safeParse(searchParams) + if (!result.success) { + // TOOD where to redirect? + redirect(`/${params.lang}/sas-x-scandic/link`) + } + const parsedParams = result.data + + const intl = await getIntl() + const redirectUri = new URL( + "/en/sas-x-scandic/callback", + env.PUBLIC_URL + ).toString() + + const state: State = { intent: parsedParams.intent } + const urlState = encodeURIComponent(JSON.stringify(state)) + const clientId = env.SAS_AUTH_CLIENTID + const sasLoginHostname = env.SAS_AUTH_ENDPOINT + const audience = "eb-partner-api" + // TODO check if this is correct scopes + const scope = encodeURIComponent("openid profile email") + + const loginLink = `${sasLoginHostname}/oauth/authorize?response_type=code&client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}&state=${urlState}&audience=${audience}` + + return ( + + + + + {intl.formatMessage({ id: "Redirecting you to SAS" })} + + + {intl.formatMessage({ + id: "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.", + })} + + + {intl.formatMessage( + { + id: "If you are not redirected automatically, please click here.", + }, + { + loginLink: (str) => ( + + {str} + + ), + } + )} + + + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/OneTimePasswordForm.module.css b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/OneTimePasswordForm.module.css new file mode 100644 index 000000000..7cd0043de --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/OneTimePasswordForm.module.css @@ -0,0 +1,92 @@ +.container-modal { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--Spacing-x3); + background-color: white; + width: 100%; + padding: var(--Spacing-x3); + text-align: center; + border-radius: var(--Corner-radius-Medium) var(--Corner-radius-Medium) 0 0; + margin-top: auto; + + @media screen and (min-width: 768px) { + & { + border-radius: var(--Corner-radius-Medium); + margin-top: initial; + width: 512px; + } + } +} + +.otp-container { + display: flex; + + gap: var(--Spacing-x1); + @media screen and (min-width: 768px) { + & { + gap: var(--Spacing-x2); + } + } + &.error .slot { + border: 1px solid var(--UI-Text-Error); + } +} + +.slot { + position: relative; + display: flex; + align-items: center; + justify-content: center; + box-sizing: content-box; + width: 34px; + height: 0px; + padding: var(--Spacing-x3) 0; + font-family: var(--typography-Body-Regular-fontFamily); + border: 1px solid var(--Base-Border-Normal); + border-radius: var(--Corner-radius-Medium); + text-align: center; + + &.active { + border: 1px solid var(--UI-Text-Active); + outline: 1px solid var(--UI-Text-Active); + } +} + +.caret { + position: absolute; + pointer-events: none; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + animation: blink 1s infinite; + + & .child { + width: 1px; + height: 16px; + background-color: var(--UI-Text-Active); + } +} + +.disabled-link { + cursor: default; + color: var(--UI-Text-Disabled); + opacity: 0.4; +} + +.error-message { + display: flex; + align-items: center; + gap: var(--Spacing-x1); +} + +@keyframes blink { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0; + } +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/OneTimePasswordForm.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/OneTimePasswordForm.tsx new file mode 100644 index 000000000..f18a55314 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/OneTimePasswordForm.tsx @@ -0,0 +1,198 @@ +"use client" + +import { cx } from "class-variance-authority" +import { OTPInput, type SlotProps } from "input-otp" +import { type ReactNode, useState, useTransition } from "react" +import { useIntl } from "react-intl" + +import { trpc } from "@/lib/trpc/client" + +import ErrorCircleFilledIcon from "@/components/Icons/ErrorCircleFilled" +import Link from "@/components/TempDesignSystem/Link" +import Body from "@/components/TempDesignSystem/Text/Body" +import Caption from "@/components/TempDesignSystem/Text/Caption" +import Footnote from "@/components/TempDesignSystem/Text/Footnote" +import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" +import { toast } from "@/components/TempDesignSystem/Toasts" + +import { GenericError } from "../components/GenericError" +import { SASModal, SASModalContactBlock } from "../components/SASModal" +import Loading from "./loading" + +import styles from "./OneTimePasswordForm.module.css" + +import type { RequestOtpError } from "@/server/routers/partners/sas/otp/request/requestOtpError" +import type { VerifyOtpError } from "@/server/routers/partners/sas/otp/verify/verifyOtpError" + +export default function OneTimePasswordForm({ + heading, + ingress, + footnote, + otpLength, + onSubmit, + error, +}: { + heading: string + ingress: string | ReactNode + footnote?: string | ReactNode + otpLength: number + onSubmit: (args: { otp: string }) => Promise + error?: ReactNode +}) { + const [isPending, startTransition] = useTransition() + const [disableResend, setDisableResend] = useState(false) + const intl = useIntl() + const [otp, setOtp] = useState("") + + const requestOtp = trpc.partner.sas.requestOtp.useMutation({}) + + if (requestOtp.isPending || isPending) { + return + } + + if (requestOtp.isError) { + const cause = requestOtp.error?.data?.cause as RequestOtpError + + const title = intl.formatMessage({ id: "Error requesting OTP" }) + const body = getRequestErrorBody(intl, cause?.errorCode) + + return ( + + {body} + + + ) + } + + function handleRequestNewOtp(event: React.MouseEvent) { + event.preventDefault() + if (disableResend) return + + setOtp("") + requestOtp.reset() + requestOtp.mutate({}) + setDisableResend(true) + + setTimeout(() => { + setDisableResend(false) + }, 15_000) + } + + function handleOTPEntered(otp: string) { + startTransition(async () => { + await onSubmit({ otp }) + }) + } + + return ( + + {heading} +
+ {ingress} +
+ + { + handleOTPEntered(otp) + }} + containerClassName={cx(styles["otp-container"], { + [styles.error]: Boolean(error), + })} + render={({ slots }) => ( + <> + {slots.map((slot, idx) => ( + + ))} + + )} + /> + {error && ( +
+ + {error} +
+ )} +
+ {footnote} + + {intl.formatMessage( + { + id: "Didn't receive a code? Resend code", + }, + { + resendOtpLink: (str) => ( + + {str} + + ), + } + )} + +
+
+ ) +} + +function Slot(props: SlotProps) { + return ( +
+ {props.char !== null &&
{props.char}
} + {props.hasFakeCaret && } +
+ ) +} + +function FakeCaret() { + return ( +
+
+
+ ) +} + +const getRequestErrorBody = ( + intl: ReturnType, + errorCode: RequestOtpError["errorCode"] +) => { + switch (errorCode) { + case "TOO_MANY_REQUESTS": + return intl.formatMessage({ + id: "Too many requests. Please try again later.", + }) + default: + return intl.formatMessage({ + id: "An error occurred while requesting a new OTP", + }) + } +} + +const getVerifyErrorBody = ( + intl: ReturnType, + errorCode: VerifyOtpError["errorCode"] +) => { + switch (errorCode) { + case "WRONG_OTP": + return intl.formatMessage({ + id: "The code you entered is incorrect. Please try again.", + }) + case "OTP_EXPIRED": + return intl.formatMessage({ + id: "OTP has expired. Please try again.", + }) + default: + return intl.formatMessage({ + id: "An error occurred while requesting a new OTP", + }) + } +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/loading.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/loading.tsx new file mode 100644 index 000000000..5b16fe51c --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/loading.tsx @@ -0,0 +1,11 @@ +import LoadingSpinner from "@/components/LoadingSpinner" + +import { SASModal } from "../components/SASModal" + +export default function Loading() { + return ( + + + + ) +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx new file mode 100644 index 000000000..cf7df475e --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx @@ -0,0 +1,128 @@ +import { cookies } from "next/headers" +import { redirect, RedirectType } from "next/navigation" +import { z } from "zod" + +import { serverClient } from "@/lib/trpc/server" + +import { getIntl } from "@/i18n" +import { safeTry } from "@/utils/safeTry" + +import { SAS_TOKEN_STORAGE_KEY } from "../sasUtils" +import OneTimePasswordForm from "./OneTimePasswordForm" + +import type { LangParams, PageArgs, SearchParams } from "@/types/params" +import type { Lang } from "@/constants/languages" + +const searchParamsSchema = z.object({ + intent: z.enum(["link"]), + to: z.string(), + error: z.enum(["invalidCode"]).optional(), +}) + +export default async function SASxScandicOneTimePasswordPage({ + searchParams, + params, +}: PageArgs & SearchParams) { + const intl = await getIntl() + const cookieStore = cookies() + const tokenCookie = cookieStore.get(SAS_TOKEN_STORAGE_KEY) + + const result = searchParamsSchema.safeParse(searchParams) + if (!result.success) { + throw new Error("Invalid search params") + } + const { intent, to, error } = result.data + + if (!verifyTokenValidity(tokenCookie?.value)) { + redirect(`/${params.lang}/sas-x-scandic/login?intent=${intent}`) + } + + const errors = { + invalidCode: intl.formatMessage({ + id: "The code you’ve entered is incorrect.", + }), + } + + async function handleOtpVerified({ otp }: { otp: string }) { + "use server" + + const [data, error] = await safeTry( + serverClient().partner.sas.verifyOtp({ otp }) + ) + + // TODO correct status? + // TODO handle all errors + // STATUS === VERIFIED => ok + // STATUS === ABUSED => otpRetryCount > otpMaxRetryCount + if (error || data?.status !== "VERIFIED") { + const search = new URLSearchParams({ + ...searchParams, + error: "invalidCode", + }).toString() + + redirect(`/${params.lang}/sas-x-scandic/otp?${search}`) + } + + switch (intent) { + case "link": + return handleLinkAccount({ lang: params.lang }) + default: + throw new Error("") + } + } + + return ( + ( + { + id: "Please enter the code sent to in order to confirm your account linking.", + }, + { + maskedContactInfo: () => ( + <> +
+ {to} +
+ + ), + } + )} + footnote={intl.formatMessage({ + id: "This verifcation is needed for additional security.", + })} + otpLength={6} + onSubmit={handleOtpVerified} + error={error ? errors[error] : undefined} + /> + ) +} + +function verifyTokenValidity(token: string | undefined) { + if (!token) { + return false + } + + try { + const decoded = JSON.parse(atob(token.split(".")[1])) + const expiry = decoded.exp * 1000 + return Date.now() < expiry + } catch (error) { + return false + } +} + +async function handleLinkAccount({ lang }: { lang: Lang }) { + const [res, error] = await safeTry(serverClient().partner.sas.linkAccount()) + if (!res || error) { + console.error("[SAS] link account error", error) + redirect(`/${lang}/sas-x-scandic/error?errorCode=link_error`) + } + + console.log("[SAS] link account response", res) + switch (res.linkingState) { + case "linked": + redirect(`/${lang}/sas-x-scandic/link/success`, RedirectType.replace) + break + } +} diff --git a/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/sasUtils.ts b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/sasUtils.ts new file mode 100644 index 000000000..383880b80 --- /dev/null +++ b/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/sasUtils.ts @@ -0,0 +1,9 @@ +import { z } from "zod" + +export const SAS_TOKEN_STORAGE_KEY = "sas-x-scandic-token" + +// TODO nonce?? +export const stateSchema = z.object({ + intent: z.literal("link"), +}) +export type State = z.infer diff --git a/app/[lang]/(partner)/layout.tsx b/app/[lang]/(partner)/layout.tsx new file mode 100644 index 000000000..f7d11f826 --- /dev/null +++ b/app/[lang]/(partner)/layout.tsx @@ -0,0 +1,68 @@ +import "@/app/globals.css" +import "@scandic-hotels/design-system/style.css" + +import { ReactQueryDevtools } from "@tanstack/react-query-devtools" +import Script from "next/script" + +import { env } from "@/env/server" +import TrpcProvider from "@/lib/trpc/Provider" + +import TokenRefresher from "@/components/Auth/TokenRefresher" +import CookieBotConsent from "@/components/CookieBot" +import StorageCleaner from "@/components/HotelReservation/EnterDetails/StorageCleaner" +import { ToastHandler } from "@/components/TempDesignSystem/Toasts" +import { preloadUserTracking } from "@/components/TrackingSDK" +import AdobeSDKScript from "@/components/TrackingSDK/AdobeSDKScript" +import GTMScript from "@/components/TrackingSDK/GTMScript" +import RouterTracking from "@/components/TrackingSDK/RouterTracking" +import { getIntl } from "@/i18n" +import ServerIntlProvider from "@/i18n/Provider" +import { setLang } from "@/i18n/serverContext" + +import type { LangParams, LayoutArgs } from "@/types/params" + +export default async function RootLayout({ + children, + params, +}: React.PropsWithChildren>) { + if (!env.SAS_ENABLED) { + return null + } + + setLang(params.lang) + preloadUserTracking() + const { defaultLocale, locale, messages } = await getIntl() + + return ( + + + + + + + + + + + {children} + + + + + + + + + + ) +} diff --git a/app/api/debug/route.ts b/app/api/debug/route.ts new file mode 100644 index 000000000..1cb663d96 --- /dev/null +++ b/app/api/debug/route.ts @@ -0,0 +1,16 @@ +import { notFound } from "next/navigation" +import { NextResponse } from "next/server" + +import { env } from "@/env/server" + +import { auth } from "@/auth" + +export const GET = async () => { + if (env.NODE_ENV !== "development") { + return notFound() + } + + const user = await auth() + console.log("[DEBUG] access-token", user?.token) + return NextResponse.json(user) +} diff --git a/components/HotelReservation/EnterDetails/Details/MemberPriceModal/modal.module.css b/components/HotelReservation/EnterDetails/Details/MemberPriceModal/modal.module.css index fbbe644ba..43fdc5f70 100644 --- a/components/HotelReservation/EnterDetails/Details/MemberPriceModal/modal.module.css +++ b/components/HotelReservation/EnterDetails/Details/MemberPriceModal/modal.module.css @@ -21,4 +21,4 @@ .modalContent { width: 352px; } -} \ No newline at end of file +} diff --git a/components/Icons/ErrorCircleFilled.tsx b/components/Icons/ErrorCircleFilled.tsx new file mode 100644 index 000000000..f4fc15ea0 --- /dev/null +++ b/components/Icons/ErrorCircleFilled.tsx @@ -0,0 +1,27 @@ +import { iconVariants } from "./variants" + +import type { IconProps } from "@/types/components/icon" + +export default function ErrorCircleFilledIcon({ + className, + color, + ...props +}: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + ) +} diff --git a/components/ProtectedLayout.tsx b/components/ProtectedLayout.tsx new file mode 100644 index 000000000..c803663b4 --- /dev/null +++ b/components/ProtectedLayout.tsx @@ -0,0 +1,69 @@ +import { headers } from "next/headers" +import { redirect } from "next/navigation" + +import { overview } from "@/constants/routes/myPages" +import { getProfile } from "@/lib/trpc/memoizedRequests" + +import { auth } from "@/auth" +import { getIntl } from "@/i18n" +import { getLang } from "@/i18n/serverContext" + +export async function ProtectedLayout({ children }: React.PropsWithChildren) { + const intl = await getIntl() + const session = await auth() + /** + * Fallback to make sure every route nested in the + * protected route group is actually protected. + */ + const h = headers() + const redirectTo = encodeURIComponent( + h.get("x-url") ?? h.get("x-pathname") ?? overview[getLang()] + ) + + const redirectURL = `/${getLang()}/login?redirectTo=${redirectTo}` + + if (!session) { + console.log(`[layout:protected] no session, redirecting to: ${redirectURL}`) + redirect(redirectURL) + } + + const user = await getProfile() + + if (user && "error" in user) { + // redirect(redirectURL) + console.error("[layout:protected] error in user", user) + console.error( + "[layout:protected] full user: ", + JSON.stringify(user, null, 4) + ) + switch (user.cause) { + case "unauthorized": // fall through + case "forbidden": // fall through + case "token_expired": + console.error( + `[layout:protected] user error, redirecting to: ${redirectURL}` + ) + redirect(redirectURL) + case "notfound": + console.error(`[layout:protected] notfound user loading error`) + break + case "unknown": + console.error(`[layout:protected] unknown user loading error`) + break + default: + console.error(`[layout:protected] unhandled user loading error`) + break + } + return

{intl.formatMessage({ id: "Something went wrong!" })}

+ } + + if (!user) { + console.error( + "[layout:protected] no user found, redirecting to: ", + redirectURL + ) + redirect(redirectURL) + } + + return children +} diff --git a/components/Redirect.tsx b/components/Redirect.tsx new file mode 100644 index 000000000..04c59cedb --- /dev/null +++ b/components/Redirect.tsx @@ -0,0 +1,19 @@ +"use client" + +import { useEffect } from "react" + +type RedirectProps = { + url: string + timeout?: number +} +export function Redirect({ url, timeout }: RedirectProps) { + useEffect(() => { + const timer = setTimeout(() => { + window.location.href = url + }, timeout || 0) + + return () => clearTimeout(timer) + }, [url, timeout]) + + return null +} diff --git a/env/server.ts b/env/server.ts index cb6add00e..faa087dd4 100644 --- a/env/server.ts +++ b/env/server.ts @@ -157,6 +157,18 @@ export const env = createEnv({ .default("false"), SENTRY_ENVIRONMENT: z.string().default("development"), SENTRY_SERVER_SAMPLERATE: z.coerce.number().default(0.001), + + // TODO: remove defaults for SAS value when we know that netlify has 'room' for it + SAS_API_ENDPOINT: z.string().default(""), + SAS_AUTH_ENDPOINT: z.string().default(""), + SAS_OCP_APIM: z.string().default(""), + SAS_AUTH_CLIENTID: z.string().default(""), + SAS_ENABLED: z + .string() + .refine((s) => s === "1" || s === "0") + .transform((s) => s === "1") + .default("0"), + CACHE_TIME_HOTELDATA: z .number() .transform(() => @@ -247,6 +259,13 @@ export const env = createEnv({ SHOW_SITE_WIDE_ALERT: process.env.SHOW_SITE_WIDE_ALERT, SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT, SENTRY_SERVER_SAMPLERATE: process.env.SENTRY_SERVER_SAMPLERATE, + + SAS_API_ENDPOINT: process.env.SAS_API_ENDPOINT, + SAS_AUTH_ENDPOINT: process.env.SAS_AUTH_ENDPOINT, + SAS_OCP_APIM: process.env.SAS_OCP_APIM, + SAS_AUTH_CLIENTID: process.env.SAS_AUTH_CLIENTID, + SAS_ENABLED: process.env.SAS, + CACHE_TIME_HOTELDATA: process.env.CACHE_TIME_HOTELDATA, CACHE_TIME_HOTELS: process.env.CACHE_TIME_HOTELS, }, diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index bd81bb5e1..001fcf36c 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -14,6 +14,7 @@ "Accessibility": "Tilgængelighed", "Accessibility at {hotel}": "Tilgængelighed på {hotel}", "Accessible Room": "Tilgængelighedsrum", + "Accounts are already linked": "Accounts are already linked", "Active": "Aktiv", "Activities": "Aktiviteter", "Add code": "Tilføj kode", @@ -57,6 +58,7 @@ "Bed type": "Seng type", "Bike friendly": "Cykelvenlig", "Birth date": "Fødselsdato", + "Birth date is required": "Birth date is required", "Book": "Book", "Book a table online": "Book et bord online", "Book parking": "Book parkering", @@ -78,6 +80,7 @@ "Bus terminal": "Busstation", "Business": "Forretning", "By accepting the Terms and Conditions for Scandic Friends I understand that my personal data will be processed in accordance with Scandic's Privacy Policy.": "Ved at acceptere vilkårene og betingelserne for Scandic Friends, forstår jeg, at mine personlige oplysninger vil blive behandlet i overensstemmelse med Scandics privatlivspolitik.", + "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.": "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.", "By paying with any of the payment methods available, I accept the terms for this booking and the general Terms & Conditions, and understand that Scandic will process my personal data for this booking in accordance with Scandic's Privacy policy. I also accept that Scandic require a valid credit card during my visit in case anything is left unpaid.": "Ved at betale med en af de tilgængelige betalingsmetoder, accepterer jeg vilkårene for denne booking og de generelle Vilkår og betingelser, og forstår, at Scandic vil behandle min personlige data i forbindelse med denne booking i henhold til Scandics Privatlivspolitik. Jeg accepterer, at Scandic kræver et gyldigt kreditkort under min besøg i tilfælde af, at noget er tilbagebetalt.", "By signing up you accept the Scandic Friends Terms and Conditions. Your membership is valid until further notice, and you can terminate your membership at any time by sending an email to Scandic's customer service": "Ved at tilmelde dig accepterer du Scandic Friends vilkår og betingelser. Dit medlemskab er gyldigt indtil videre, og du kan til enhver tid opsige dit medlemskab ved at sende en e-mail til Scandics kundeservice", "Campaign": "Kampagne", @@ -113,6 +116,7 @@ "Complete booking & go to payment": "Udfyld booking & gå til betaling", "Complete the booking": "Fuldfør bookingen", "Contact information": "Kontaktoplysninger", + "Contact our memberservice": "Contact our memberservice", "Contact us": "Kontakt os", "Continue": "Blive ved", "Could not find requested resource": "Kunne ikke finde den anmodede ressource", @@ -127,11 +131,13 @@ "Current password": "Nuværende kodeord", "Customer service": "Kundeservice", "Date of Birth": "Fødselsdato", + "Date of birth not matching": "Date of birth not matching", "Day": "Dag", "Description": "Beskrivelse", "Destination": "Destination", "Destinations & hotels": "Destinationer & hoteller", "Details": "Detaljer", + "Didn't receive a code? Resend code": "Didn't receive a code? Resend code", "Discard changes": "Kassér ændringer", "Discard unsaved changes?": "Slette ændringer, der ikke er gemt?", "Discover": "Opdag", @@ -184,6 +190,7 @@ "Free parking": "Gratis parkering", "Free rebooking": "Gratis ombooking", "Friday": "Fredag", + "Friends with Benefits": "Friends with Benefits", "From": "Fra", "Garage": "Garage", "Get inspired": "Bliv inspireret", @@ -214,9 +221,11 @@ "I accept": "Jeg accepterer", "I accept the terms and conditions": "Jeg accepterer vilkårene", "I would like to get my booking confirmation via sms": "Jeg vil gerne få min booking bekræftelse via SMS", + "If you are not redirected automatically, please click here.": "If you are not redirected automatically, please click here.", "In adults bed": "i de voksnes seng", "In crib": "i tremmeseng", "In extra bed": "i ekstra seng", + "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.": "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.", "Included": "Inkluderet", "IndoorPool": "Indendørs pool", "Is there anything else you would like us to know before your arrival?": "Er der andet, du gerne vil have os til at vide, før din ankomst?", @@ -244,6 +253,8 @@ "Level 7": "Niveau 7", "Level up to unlock": "Stig i niveau for at låse op", "Level {level}": "Niveau {level}", + "Link my accounts": "Link my accounts", + "Link your accounts": "Link your accounts", "Location": "Beliggenhed", "Locations": "Placeringer", "Log in": "Log på", @@ -346,6 +357,7 @@ "Phone is required": "Telefonnummer er påkrævet", "Phone number": "Telefonnummer", "Please enter a valid phone number": "Indtast venligst et gyldigt telefonnummer", + "Please enter the code sent to in order to confirm your account linking.": "Please enter the code sent to in order to confirm your account linking.", "Please note that this is mandatory, and that your card will only be charged in the event of a no-show.": "Vær opmærksom på, at dette er påkrævet, og at dit kort kun vil blive opkrævet i tilfælde af en no-show.", "Points": "Point", "Points being calculated": "Point udregnes", @@ -375,6 +387,8 @@ "Read more & book a table": "Read more & book a table", "Read more about the hotel": "Læs mere om hotellet", "Read more about wellness & exercise": "Read more about wellness & exercise", + "Redirecting you to SAS": "Redirecting you to SAS", + "Redirecting you to my pages.": "Redirecting you to my pages.", "Reference #{bookingNr}": "Reference #{bookingNr}", "Relax": "Slap af", "Remove card from member profile": "Fjern kortet fra medlemsprofilen", @@ -453,6 +467,7 @@ "Terms and conditions": "Vilkår og betingelser", "Thank you": "Tak", "Thank you for booking with us! We look forward to welcoming you and hope you have a pleasant stay. If you have any questions or need to make changes to your reservation, please contact us.": "Tak fordi du bookede hos os! Vi glæder os til at byde dig velkommen og håber du får et behageligt ophold. Hvis du har spørgsmål eller har brug for at foretage ændringer i din reservation, bedes du kontakte os.", + "The code you’ve entered is incorrect.": "The code you’ve entered is incorrect.", "The new price is": "Nyprisen er", "The price has increased": "Prisen er steget", "The price has increased since you selected your room.": "Prisen er steget, efter at du har valgt dit værelse.", @@ -463,6 +478,7 @@ "Things nearby {hotelName}": "Ting i nærheden af {hotelName}", "This room is equipped with": "Dette værelse er udstyret med", "This room is not available": "Dette værelse er ikke tilgængeligt", + "This verifcation is needed for additional security.": "This verifcation is needed for additional security.", "Thursday": "Torsdag", "Times": "Tider", "To get the member price {price}, log in or join when completing the booking.": "For at få medlemsprisen {price}, log ind eller tilmeld dig, når du udfylder bookingen.", @@ -484,16 +500,22 @@ "User information": "Brugeroplysninger", "VAT {vat}%": "Moms {vat}%", "Valid through {expirationDate}": "Gyldig til og med {expirationDate}", + "Verification code": "Verification code", "View as list": "Vis som liste", "View as map": "Vis som kort", + "View your account": "View your account", "View your booking": "Se din booking", "Visiting address": "Besøgsadresse", "Voucher": "Voucher", "We could not add a card right now, please try again later.": "Vi kunne ikke tilføje et kort lige nu. Prøv venligst igen senere.", + "We could not connect your accounts": "We could not connect your accounts", + "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.": "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.", "We couldn't find a matching location for your search.": "Vi kunne ikke finde en matchende lokation til din søgning.", "We had an issue processing your booking. Please try again. No charges have been made.": "Vi havde et problem med at behandle din booking. Prøv venligst igen. Ingen gebyrer er blevet opkrævet.", "We have a special gift waiting for you!": "Vi har en speciel gave, der venter på dig!", "We look forward to your visit!": "Vi ser frem til dit besøg!", + "We require this additional information in order to match your Scandic account with your EuroBonus account.": "We require this additional information in order to match your Scandic account with your EuroBonus account.", + "We successfully connected your accounts!": "We successfully connected your accounts!", "We're sorry": "Vi beklager", "Wednesday": "Onsdag", "Weekday": "Ugedag", @@ -522,8 +544,10 @@ "You have no previous stays.": "Du har ingen tidligere ophold.", "You have no upcoming stays.": "Du har ingen kommende ophold.", "You have now cancelled your payment.": "Du har nu annulleret din betaling.", + "You must accept the terms and conditions": "You must accept the terms and conditions", "You'll find all your gifts in 'My benefits'": "Du finder alle dine gaver i 'Mine fordele'", "Your Challenges Conquer & Earn!": "Dine udfordringer Overvind og tjen!", + "Your accounts are connected": "Your accounts are connected", "Your booking(s) is confirmed but we could not verify your membership. If you have booked with a member discount, you'll either need to present your existing membership number upon check-in, become a member or pay the price difference at the hotel. Signing up is preferably done online before the stay.": "Din booking er bekræftet, men vi kunne ikke verificere dit medlemskab. Hvis du har booket med et medlemstilbud, skal du enten vise dit eksisterende medlemskab ved check-in, blive medlem eller betale prisdifferencen ved check-in. Tilmelding er foretrukket online før opholdet.", "Your card was successfully removed!": "Dit kort blev fjernet!", "Your card was successfully saved!": "Dit kort blev gemt!", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index 5700320d2..995e9a404 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -14,6 +14,7 @@ "Accessibility": "Zugänglichkeit", "Accessibility at {hotel}": "Barrierefreiheit im {hotel}", "Accessible Room": "Barrierefreies Zimmer", + "Accounts are already linked": "Accounts are already linked", "Active": "Aktiv", "Activities": "Aktivitäten", "Add code": "Code hinzufügen", @@ -57,6 +58,7 @@ "Bed type": "Bettentyp", "Bike friendly": "Fahrradfreundlich", "Birth date": "Geburtsdatum", + "Birth date is required": "Birth date is required", "Book": "Buchen", "Book a table online": "Tisch online buchen", "Book parking": "Parkplatz buchen", @@ -77,6 +79,7 @@ "Breakfast selection in next step.": "Frühstücksauswahl in nächsten Schritt.", "Business": "Geschäft", "By accepting the Terms and Conditions for Scandic Friends I understand that my personal data will be processed in accordance with Scandic's Privacy Policy.": "Mit der Annahme der Allgemeinen Geschäftsbedingungen für Scandic Friends erkläre ich mich damit einverstanden, dass meine persönlichen Daten in Übereinstimmung mit der Datenschutzrichtlinie von Scandic verarbeitet werden.", + "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.": "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.", "By paying with any of the payment methods available, I accept the terms for this booking and the general Terms & Conditions, and understand that Scandic will process my personal data for this booking in accordance with Scandic's Privacy policy. I also accept that Scandic require a valid credit card during my visit in case anything is left unpaid.": "Mit der Zahlung über eine der verfügbaren Zahlungsmethoden akzeptiere ich die Buchungsbedingungen und die allgemeinen Geschäftsbedingungen und verstehe, dass Scandic meine personenbezogenen Daten im Zusammenhang mit dieser Buchung gemäß der Scandic Datenschutzrichtlinie verarbeitet. Ich akzeptiere, dass Scandic während meines Aufenthalts eine gültige Kreditkarte für eventuelle Rückerstattungen benötigt.", "By signing up you accept the Scandic Friends Terms and Conditions. Your membership is valid until further notice, and you can terminate your membership at any time by sending an email to Scandic's customer service": "Mit Ihrer Anmeldung akzeptieren Sie die Allgemeinen Geschäftsbedingungen von Scandic Friends. Ihre Mitgliedschaft ist bis auf Weiteres gültig und Sie können sie jederzeit kündigen, indem Sie eine E-Mail an den Kundenservice von Scandic senden.", "Campaign": "Kampagne", @@ -112,6 +115,7 @@ "Complete booking & go to payment": "Buchung abschließen & zur Bezahlung gehen", "Complete the booking": "Buchung abschließen", "Contact information": "Kontaktinformationen", + "Contact our memberservice": "Contact our memberservice", "Contact us": "Kontaktieren Sie uns", "Continue": "Weitermachen", "Could not find requested resource": "Die angeforderte Ressource konnte nicht gefunden werden.", @@ -126,11 +130,13 @@ "Current password": "Aktuelles Passwort", "Customer service": "Kundendienst", "Date of Birth": "Geburtsdatum", + "Date of birth not matching": "Date of birth not matching", "Day": "Tag", "Description": "Beschreibung", "Destination": "Bestimmungsort", "Destinations & hotels": "Reiseziele & Hotels", "Details": "Details", + "Didn't receive a code? Resend code": "Didn't receive a code? Resend code", "Discard changes": "Änderungen verwerfen", "Discard unsaved changes?": "Nicht gespeicherte Änderungen verwerfen?", "Discover": "Entdecken", @@ -183,6 +189,7 @@ "Free parking": "Kostenloses Parken", "Free rebooking": "Kostenlose Umbuchung", "Friday": "Freitag", + "Friends with Benefits": "Friends with Benefits", "From": "Fromm", "Garage": "Garage", "Get inspired": "Lassen Sie sich inspieren", @@ -213,9 +220,11 @@ "I accept": "Ich akzeptiere", "I accept the terms and conditions": "Ich akzeptiere die Geschäftsbedingungen", "I would like to get my booking confirmation via sms": "Ich möchte meine Buchungsbestätigung per SMS erhalten", + "If you are not redirected automatically, please click here.": "If you are not redirected automatically, please click here.", "In adults bed": "Im Bett der Eltern", "In crib": "im Kinderbett", "In extra bed": "im zusätzlichen Bett", + "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.": "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.", "Included": "Iinklusive", "IndoorPool": "Innenpool", "Is there anything else you would like us to know before your arrival?": "Gibt es noch etwas, das Sie uns vor Ihrer Ankunft mitteilen möchten?", @@ -243,6 +252,8 @@ "Level 7": "Level 7", "Level up to unlock": "Zum Freischalten aufsteigen", "Level {level}": "Level {level}", + "Link my accounts": "Link my accounts", + "Link your accounts": "Link your accounts", "Location": "Ort", "Locations": "Orte", "Log in": "Anmeldung", @@ -344,6 +355,7 @@ "Phone is required": "Telefon ist erforderlich", "Phone number": "Telefonnummer", "Please enter a valid phone number": "Bitte geben Sie eine gültige Telefonnummer ein", + "Please enter the code sent to in order to confirm your account linking.": "Please enter the code sent to in order to confirm your account linking.", "Please note that this is mandatory, and that your card will only be charged in the event of a no-show.": "Bitte beachten Sie, dass dies erforderlich ist und dass Ihr Kreditkartenkonto nur in einem No-Show-Fall belastet wird.", "Points": "Punkte", "Points being calculated": "Punkte werden berechnet", @@ -373,6 +385,8 @@ "Read more & book a table": "Read more & book a table", "Read more about the hotel": "Lesen Sie mehr über das Hotel", "Read more about wellness & exercise": "Read more about wellness & exercise", + "Redirecting you to SAS": "Redirecting you to SAS", + "Redirecting you to my pages.": "Redirecting you to my pages.", "Reference #{bookingNr}": "Referenz #{bookingNr}", "Relax": "Entspannen", "Remove card from member profile": "Karte aus dem Mitgliedsprofil entfernen", @@ -452,6 +466,7 @@ "Terms and conditions": "Geschäftsbedingungen", "Thank you": "Danke", "Thank you for booking with us! We look forward to welcoming you and hope you have a pleasant stay. If you have any questions or need to make changes to your reservation, please contact us.": "Vielen Dank, dass Sie bei uns gebucht haben! Wir freuen uns, Sie bei uns begrüßen zu dürfen und wünschen Ihnen einen angenehmen Aufenthalt. Wenn Sie Fragen haben oder Änderungen an Ihrer Buchung vornehmen müssen, kontaktieren Sie uns bitte..", + "The code you’ve entered is incorrect.": "The code you’ve entered is incorrect.", "The new price is": "Der neue Preis beträgt", "The price has increased": "Der Preis ist gestiegen", "The price has increased since you selected your room.": "Der Preis ist gestiegen, nachdem Sie Ihr Zimmer ausgewählt haben.", @@ -461,6 +476,7 @@ "Things nearby {hotelName}": "Dinge in der Nähe von {hotelName}", "This room is equipped with": "Dieses Zimmer ist ausgestattet mit", "This room is not available": "Dieses Zimmer ist nicht verfügbar", + "This verifcation is needed for additional security.": "This verifcation is needed for additional security.", "Thursday": "Donnerstag", "Times": "Zeiten", "To get the member price {price}, log in or join when completing the booking.": "Um den Mitgliederpreis von {price} zu erhalten, loggen Sie sich ein oder treten Sie Scandic Friends bei, wenn Sie die Buchung abschließen.", @@ -482,16 +498,22 @@ "User information": "Nutzerinformation", "VAT {vat}%": "MwSt. {vat}%", "Valid through {expirationDate}": "Gültig bis {expirationDate}", + "Verification code": "Verification code", "View as list": "Als Liste anzeigen", "View as map": "Als Karte anzeigen", + "View your account": "View your account", "View your booking": "Ihre Buchung ansehen", "Visiting address": "Besuchsadresse", "Voucher": "Gutschein", "We could not add a card right now, please try again later.": "Wir konnten momentan keine Karte hinzufügen. Bitte versuchen Sie es später noch einmal.", + "We could not connect your accounts": "We could not connect your accounts", + "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.": "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.", "We couldn't find a matching location for your search.": "Wir konnten keinen passenden Standort für Ihre Suche finden.", "We had an issue processing your booking. Please try again. No charges have been made.": "Wir hatten ein Problem beim Verarbeiten Ihrer Buchung. Bitte versuchen Sie es erneut. Es wurden keine Gebühren erhoben.", "We have a special gift waiting for you!": "Wir haben ein besonderes Geschenk für Sie!", "We look forward to your visit!": "Wir freuen uns auf Ihren Besuch!", + "We require this additional information in order to match your Scandic account with your EuroBonus account.": "We require this additional information in order to match your Scandic account with your EuroBonus account.", + "We successfully connected your accounts!": "We successfully connected your accounts!", "We're sorry": "Es tut uns leid", "Wednesday": "Mittwoch", "Weekday": "Wochentag", @@ -520,8 +542,10 @@ "You have no previous stays.": "Sie haben keine vorherigen Aufenthalte.", "You have no upcoming stays.": "Sie haben keine bevorstehenden Aufenthalte.", "You have now cancelled your payment.": "Sie haben jetzt Ihre Zahlung abgebrochen.", + "You must accept the terms and conditions": "You must accept the terms and conditions", "You'll find all your gifts in 'My benefits'": "Alle Ihre Geschenke finden Sie unter „Meine Vorteile“", "Your Challenges Conquer & Earn!": "Meistern Sie Ihre Herausforderungen und verdienen Sie Geld!", + "Your accounts are connected": "Your accounts are connected", "Your booking(s) is confirmed but we could not verify your membership. If you have booked with a member discount, you'll either need to present your existing membership number upon check-in, become a member or pay the price difference at the hotel. Signing up is preferably done online before the stay.": "Ihre Buchung ist bestätigt, aber wir konnten Ihr Mitglied nicht verifizieren. Wenn Sie mit einem Mitgliederrabatt gebucht haben, müssen Sie entweder Ihr vorhandenes Mitgliedschaftsnummer bei der Anreise präsentieren, ein Mitglied werden oder die Preisdifferenz bei der Anreise bezahlen. Die Anmeldung ist vorzugsweise online vor der Aufenthaltsdauer erfolgreich.", "Your card was successfully removed!": "Ihre Karte wurde erfolgreich entfernt!", "Your card was successfully saved!": "Ihre Karte wurde erfolgreich gespeichert!", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index acb978d1d..22ac55f31 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -1,4 +1,5 @@ { + "+46 8 517 517 00": "+46 8 517 517 00", "Included (based on availability)": "Included (based on availability)", "Total price (incl VAT)": "Total price (incl VAT)", "{amount} 0 {currency}/night per adult": "{amount} 0 {currency}/night per adult", @@ -14,6 +15,7 @@ "Accessibility": "Accessibility", "Accessibility at {hotel}": "Accessibility at {hotel}", "Accessible Room": "Accessibility room", + "Accounts are already linked": "Accounts are already linked", "Active": "Active", "Activities": "Activities", "Add code": "Add code", @@ -49,6 +51,7 @@ "Attractions": "Attractions", "Average price per night": "Average price per night", "Away from elevator": "Away from elevator", + "Back": "Back", "Back to scandichotels.com": "Back to scandichotels.com", "Back to top": "Back to top", "Bar": "Bar", @@ -58,6 +61,7 @@ "Bed type": "Bed type", "Bike friendly": "Bike friendly", "Birth date": "Birth date", + "Birth date is required": "Birth date is required", "Book": "Book", "Book a table online": "Book a table online", "Book another stay": "Book another stay", @@ -82,6 +86,7 @@ "Bus terminal": "Bus terminal", "Business": "Business", "By accepting the Terms and Conditions for Scandic Friends I understand that my personal data will be processed in accordance with Scandic's Privacy Policy.": "By accepting the Terms and Conditions for Scandic Friends I understand that my personal data will be processed in accordance with Scandic's Privacy Policy.", + "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.": "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.", "By paying with any of the payment methods available, I accept the terms for this booking and the general Terms & Conditions, and understand that Scandic will process my personal data for this booking in accordance with Scandic's Privacy policy. I also accept that Scandic require a valid credit card during my visit in case anything is left unpaid.": "By paying with any of the payment methods available, I accept the terms for this booking and the general Terms & Conditions, and understand that Scandic will process my personal data for this booking in accordance with Scandic's Privacy policy. I also accept that Scandic require a valid credit card during my visit in case anything is left unpaid.", "By signing up you accept the Scandic Friends Terms and Conditions. Your membership is valid until further notice, and you can terminate your membership at any time by sending an email to Scandic's customer service": "By signing up you accept the Scandic Friends Terms and Conditions. Your membership is valid until further notice, and you can terminate your membership at any time by sending an email to Scandic's customer service", "Campaign": "Campaign", @@ -123,6 +128,7 @@ "Complete booking & go to payment": "Complete booking & go to payment", "Complete the booking": "Complete the booking", "Contact information": "Contact information", + "Contact our memberservice": "Contact our memberservice", "Contact us": "Contact us", "Continue": "Continue", "Copied to clipboard": "Copied to clipboard", @@ -139,12 +145,14 @@ "Current password": "Current password", "Customer service": "Customer service", "Date of Birth": "Date of Birth", + "Date of birth not matching": "Date of birth not matching", "Day": "Day", "Description": "Description", "Destination": "Destination", "Destinations & hotels": "Destinations & hotels", "Details": "Details", "Dialog": "Dialog", + "Didn't receive a code? Resend code": "Didn't receive a code? Resend code", "Discard changes": "Discard changes", "Discard unsaved changes?": "Discard unsaved changes?", "Discover": "Discover", @@ -200,6 +208,7 @@ "Free until": "Free until", "Friday": "Friday", "Friend no. {value}": "Friend no. {value}", + "Friends with Benefits": "Friends with Benefits", "From": "From", "Garage": "Garage", "Get inspired": "Get inspired", @@ -233,9 +242,11 @@ "I accept": "I accept", "I accept the terms and conditions": "I accept the terms and conditions", "I would like to get my booking confirmation via sms": "I would like to get my booking confirmation via sms", + "If you are not redirected automatically, please click here.": "If you are not redirected automatically, please click here.", "In adults bed": "In adults bed", "In crib": "In crib", "In extra bed": "In extra bed", + "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.": "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.", "Included": "Included", "IndoorPool": "Indoor pool", "Is there anything else you would like us to know before your arrival?": "Is there anything else you would like us to know before your arrival?", @@ -263,6 +274,8 @@ "Level 7": "Level 7", "Level up to unlock": "Level up to unlock", "Level {level}": "Level {level}", + "Link my accounts": "Link my accounts", + "Link your accounts": "Link your accounts", "Location": "Location", "Locations": "Locations", "Log in": "Log in", @@ -377,6 +390,7 @@ "Phone is required": "Phone is required", "Phone number": "Phone number", "Please enter a valid phone number": "Please enter a valid phone number", + "Please enter the code sent to in order to confirm your account linking.": "Please enter the code sent to in order to confirm your account linking.", "Please note that this is mandatory, and that your card will only be charged in the event of a no-show.": "Please note that this is mandatory, and that your card will only be charged in the event of a no-show.", "Please try and change your search for this destination or see alternative hotels.": "Please try and change your search for this destination or see alternative hotels.", "Points": "Points", @@ -415,6 +429,8 @@ "Rebooking": "Rebooking", "Redeem benefit": "Redeem benefit", "Redeemed & valid through:": "Redeemed & valid through:", + "Redirecting you to SAS": "Redirecting you to SAS", + "Redirecting you to my pages.": "Redirecting you to my pages.", "Reference #{bookingNr}": "Reference #{bookingNr}", "Relax": "Relax", "Remove card from member profile": "Remove card from member profile", @@ -499,6 +515,7 @@ "Terms and conditions": "Terms and conditions", "Thank you": "Thank you", "Thank you for booking with us! We look forward to welcoming you and hope you have a pleasant stay. If you have any questions or need to make changes to your reservation, please contact us.": "Thank you for booking with us! We look forward to welcoming you and hope you have a pleasant stay. If you have any questions or need to make changes to your reservation, please contact us.", + "The code you’ve entered is incorrect.": "The code you’ve entered is incorrect.", "The new price is": "The new price is", "The price has increased": "The price has increased", "The price has increased since you selected your room.": "The price has increased since you selected your room.", @@ -508,6 +525,7 @@ "Things nearby {hotelName}": "Things nearby {hotelName}", "This room is equipped with": "This room is equipped with", "This room is not available": "This room is not available", + "This verifcation is needed for additional security.": "This verifcation is needed for additional security.", "Thursday": "Thursday", "Times": "Times", "To get the member price {price}, log in or join when completing the booking.": "To get the member price {price}, log in or join when completing the booking.", @@ -531,19 +549,25 @@ "VAT amount": "VAT amount", "VAT {vat}%": "VAT {vat}%", "Valid through {expirationDate}": "Valid through {expirationDate}", + "Verification code": "Verification code", "View and buy add-ons": "View and buy add-ons", "View as list": "View as list", "View as map": "View as map", "View room details": "View room details", "View terms": "View terms", + "View your account": "View your account", "View your booking": "View your booking", "Visiting address": "Visiting address", "Voucher": "Voucher", "We could not add a card right now, please try again later.": "We could not add a card right now, please try again later.", + "We could not connect your accounts": "We could not connect your accounts", + "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.": "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.", "We couldn't find a matching location for your search.": "We couldn't find a matching location for your search.", "We had an issue processing your booking. Please try again. No charges have been made.": "We had an issue processing your booking. Please try again. No charges have been made.", "We have a special gift waiting for you!": "We have a special gift waiting for you!", "We look forward to your visit!": "We look forward to your visit!", + "We require this additional information in order to match your Scandic account with your EuroBonus account.": "We require this additional information in order to match your Scandic account with your EuroBonus account.", + "We successfully connected your accounts!": "We successfully connected your accounts!", "We're sorry": "We're sorry", "Wednesday": "Wednesday", "Weekday": "Weekday", @@ -573,8 +597,10 @@ "You have no previous stays.": "You have no previous stays.", "You have no upcoming stays.": "You have no upcoming stays.", "You have now cancelled your payment.": "You have now cancelled your payment.", + "You must accept the terms and conditions": "You must accept the terms and conditions", "You'll find all your gifts in 'My benefits'": "You'll find all your gifts in 'My benefits'", "Your Challenges Conquer & Earn!": "Your Challenges Conquer & Earn!", + "Your accounts are connected": "Your accounts are connected", "Your booking(s) is confirmed but we could not verify your membership. If you have booked with a member discount, you'll either need to present your existing membership number upon check-in, become a member or pay the price difference at the hotel. Signing up is preferably done online before the stay.": "Your booking(s) is confirmed but we could not verify your membership. If you have booked with a member discount, you'll either need to present your existing membership number upon check-in, become a member or pay the price difference at the hotel. Signing up is preferably done online before the stay.", "Your card was successfully removed!": "Your card was successfully removed!", "Your card was successfully saved!": "Your card was successfully saved!", @@ -596,6 +622,7 @@ "monday": "monday", "next level: {nextLevel}": "next level: {nextLevel}", "night": "night", + "or": "or", "points": "points", "saturday": "saturday", "sunday": "sunday", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index 91a5f6edf..075bcb38f 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -14,6 +14,7 @@ "Accessibility": "Saavutettavuus", "Accessibility at {hotel}": "Esteettömyys {hotel}", "Accessible Room": "Esteetön huone", + "Accounts are already linked": "Accounts are already linked", "Active": "Aktiivinen", "Activities": "Aktiviteetit", "Add code": "Lisää koodi", @@ -57,6 +58,7 @@ "Bed type": "Vuodetyyppi", "Bike friendly": "Pyöräystävällinen", "Birth date": "Syntymäaika", + "Birth date is required": "Birth date is required", "Book": "Varaa", "Book a table online": "Varaa pöytä verkossa", "Book parking": "Varaa pysäköinti", @@ -78,6 +80,7 @@ "Bus terminal": "Bussiasema", "Business": "Business", "By accepting the Terms and Conditions for Scandic Friends I understand that my personal data will be processed in accordance with Scandic's Privacy Policy.": "Kyllä, hyväksyn Scandic Friends -jäsenyyttä koskevat ehdot ja ymmärrän, että Scandic käsittelee henkilötietojani Scandicin Tietosuojaselosteen mukaisesti.", + "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.": "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.", "By paying with any of the payment methods available, I accept the terms for this booking and the general Terms & Conditions, and understand that Scandic will process my personal data for this booking in accordance with Scandic's Privacy policy. I also accept that Scandic require a valid credit card during my visit in case anything is left unpaid.": "Maksamalla minkä tahansa saatavilla olevan maksutavan avulla hyväksyn tämän varauksen ehdot ja yleiset ehdot ja ehtoja, ja ymmärrän, että Scandic käsittelee minun henkilötietoni tässä varauksessa mukaisesti Scandicin tietosuojavaltuuden mukaisesti. Hyväksyn myös, että Scandic vaatii validin luottokortin majoituksen ajan, jos jokin jää maksamatta.", "By signing up you accept the Scandic Friends Terms and Conditions. Your membership is valid until further notice, and you can terminate your membership at any time by sending an email to Scandic's customer service": "Rekisteröitymällä hyväksyt Scandic Friendsin käyttöehdot. Jäsenyytesi on voimassa toistaiseksi ja voit lopettaa jäsenyytesi milloin tahansa lähettämällä sähköpostia Scandicin asiakaspalveluun", "Campaign": "Kampanja", @@ -113,6 +116,7 @@ "Complete booking & go to payment": "Täydennä varaus & siirry maksamaan", "Complete the booking": "Täydennä varaus", "Contact information": "Yhteystiedot", + "Contact our memberservice": "Contact our memberservice", "Contact us": "Ota meihin yhteyttä", "Continue": "Jatkaa", "Could not find requested resource": "Pyydettyä resurssia ei löytynyt", @@ -127,11 +131,13 @@ "Current password": "Nykyinen salasana", "Customer service": "Asiakaspalvelu", "Date of Birth": "Syntymäaika", + "Date of birth not matching": "Date of birth not matching", "Day": "Päivä", "Description": "Kuvaus", "Destination": "Kohde", "Destinations & hotels": "Kohteet ja hotellit", "Details": "Tiedot", + "Didn't receive a code? Resend code": "Didn't receive a code? Resend code", "Discard changes": "Hylkää muutokset", "Discard unsaved changes?": "Hylkäätkö tallentamattomat muutokset?", "Discover": "Löydä", @@ -184,6 +190,7 @@ "Free parking": "Ilmainen pysäköinti", "Free rebooking": "Ilmainen uudelleenvaraus", "Friday": "Perjantai", + "Friends with Benefits": "Friends with Benefits", "From": "From", "Garage": "Autotalli", "Get inspired": "Inspiroidu", @@ -214,9 +221,11 @@ "I accept": "Hyväksyn", "I accept the terms and conditions": "Hyväksyn käyttöehdot", "I would like to get my booking confirmation via sms": "Haluan saada varauksen vahvistuksen SMS-viestillä", + "If you are not redirected automatically, please click here.": "If you are not redirected automatically, please click here.", "In adults bed": "Aikuisten vuoteessa", "In crib": "Pinnasängyssä", "In extra bed": "Oma vuodepaikka", + "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.": "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.", "Included": "Sisälly hintaan", "IndoorPool": "Sisäuima-allas", "Is there anything else you would like us to know before your arrival?": "Onko jotain muuta, mitä haluaisit meidän tietävän ennen saapumistasi?", @@ -244,6 +253,8 @@ "Level 7": "Taso 7", "Level up to unlock": "Nosta taso avataksesi lukituksen", "Level {level}": "Taso {level}", + "Link my accounts": "Link my accounts", + "Link your accounts": "Link your accounts", "Location": "Sijainti", "Locations": "Sijainnit", "Log in": "Kirjaudu sisään", @@ -346,6 +357,7 @@ "Phone is required": "Puhelin vaaditaan", "Phone number": "Puhelinnumero", "Please enter a valid phone number": "Ole hyvä ja näppäile voimassaoleva puhelinnumero", + "Please enter the code sent to in order to confirm your account linking.": "Please enter the code sent to in order to confirm your account linking.", "Please note that this is mandatory, and that your card will only be charged in the event of a no-show.": "Huomaa, että tämä on pakollinen, ja että maksukorttiisi kirjataan vain, jos varausmyyntiä ei tapahtu.", "Points": "Pisteet", "Points being calculated": "Pisteitä lasketaan", @@ -375,6 +387,8 @@ "Read more & book a table": "Read more & book a table", "Read more about the hotel": "Lue lisää hotellista", "Read more about wellness & exercise": "Read more about wellness & exercise", + "Redirecting you to SAS": "Redirecting you to SAS", + "Redirecting you to my pages.": "Redirecting you to my pages.", "Reference #{bookingNr}": "Referenssi #{bookingNr}", "Relax": "Rentoutua", "Remove card from member profile": "Poista kortti jäsenprofiilista", @@ -455,6 +469,7 @@ "Terms and conditions": "Säännöt ja ehdot", "Thank you": "Kiitos", "Thank you for booking with us! We look forward to welcoming you and hope you have a pleasant stay. If you have any questions or need to make changes to your reservation, please contact us.": "Kiitos, että teit varauksen meiltä! Toivotamme sinut tervetulleeksi ja toivomme sinulle miellyttävää oleskelua. Jos sinulla on kysyttävää tai haluat tehdä muutoksia varaukseesi, ota meihin yhteyttä.", + "The code you’ve entered is incorrect.": "The code you’ve entered is incorrect.", "The new price is": "Uusi hinta on", "The price has increased": "Hinta on noussut", "The price has increased since you selected your room.": "Hinta on noussut, koska valitsit huoneen.", @@ -464,6 +479,7 @@ "Things nearby {hotelName}": "Lähellä olevia asioita {hotelName}", "This room is equipped with": "Tämä huone on varustettu", "This room is not available": "Tämä huone ei ole käytettävissä", + "This verifcation is needed for additional security.": "This verifcation is needed for additional security.", "Times": "Ajat", "To get the member price {price}, log in or join when completing the booking.": "Jäsenhintaan saavat sisäänkirjautuneet tai liittyneet jäsenet.", "To secure your reservation, we kindly ask you to provide your payment card details. Rest assured, no charges will be made at this time.": "Varmistaaksesi varauksen, pyydämme sinua antamaan meille maksukortin tiedot. Varmista, että ei veloiteta maksusi tällä hetkellä.", @@ -484,16 +500,22 @@ "User information": "Käyttäjän tiedot", "VAT {vat}%": "ALV {vat}%", "Valid through {expirationDate}": "Voimassa {expirationDate} asti", + "Verification code": "Verification code", "View as list": "Näytä listana", "View as map": "Näytä kartalla", + "View your account": "View your account", "View your booking": "Näytä varauksesi", "Visiting address": "Käyntiosoite", "Voucher": "Ravintolakuponki", "We could not add a card right now, please try again later.": "Emme voineet lisätä korttia juuri nyt. Yritä myöhemmin uudelleen.", + "We could not connect your accounts": "We could not connect your accounts", + "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.": "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.", "We couldn't find a matching location for your search.": "Emme löytäneet hakuasi vastaavaa sijaintia.", "We had an issue processing your booking. Please try again. No charges have been made.": "Meillä oli ongelma varauksen käsittelyssä. Yritä uudelleen. Ei maksuja on tehty.", "We have a special gift waiting for you!": "Meillä on erityinen lahja odottamassa sinua!", "We look forward to your visit!": "Odotamme innolla vierailuasi!", + "We require this additional information in order to match your Scandic account with your EuroBonus account.": "We require this additional information in order to match your Scandic account with your EuroBonus account.", + "We successfully connected your accounts!": "We successfully connected your accounts!", "We're sorry": "Olemme pahoillamme", "Wednesday": "Keskiviikko", "Weekday": "Arkipäivä", @@ -522,6 +544,8 @@ "You have no previous stays.": "Sinulla ei ole aiempia majoituksia.", "You have no upcoming stays.": "Sinulla ei ole tulevia majoituksia.", "You have now cancelled your payment.": "Sinut nyt peruutit maksun.", + "You must accept the terms and conditions": "You must accept the terms and conditions", + "Your accounts are connected": "Your accounts are connected", "Your booking(s) is confirmed but we could not verify your membership. If you have booked with a member discount, you'll either need to present your existing membership number upon check-in, become a member or pay the price difference at the hotel. Signing up is preferably done online before the stay.": "Varauksesi on vahvistettu, mutta jäsenyytesi ei voitu vahvistaa. Jos olet bookeutunut jäsenyysalennoilla, sinun on joko esitettävä olemassa olevan jäsenyysnumero tarkistukseen, tulla jäseneksi tai maksamaan hinnan eron hotellissa. Jäsenyyden tilittäminen on suositeltavampaa tehdä verkkoon ennen majoittumista.", "Your card was successfully removed!": "Korttisi poistettiin onnistuneesti!", "Your card was successfully saved!": "Korttisi tallennettu onnistuneesti!", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index 5060a0731..ed501540d 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -14,6 +14,7 @@ "Accessibility": "Tilgjengelighet", "Accessibility at {hotel}": "Tilgjengelighet på {hotel}", "Accessible Room": "Tilgjengelighetsrom", + "Accounts are already linked": "Accounts are already linked", "Active": "Aktiv", "Activities": "Aktiviteter", "Add code": "Legg til kode", @@ -57,6 +58,7 @@ "Bed type": "Seng type", "Bike friendly": "Sykkelvennlig", "Birth date": "Fødselsdato", + "Birth date is required": "Birth date is required", "Book": "Bestill", "Book a table online": "Bestill bord online", "Book parking": "Bestill parkering", @@ -78,6 +80,7 @@ "Bus terminal": "Bussterminal", "Business": "Forretnings", "By accepting the Terms and Conditions for Scandic Friends I understand that my personal data will be processed in accordance with Scandic's Privacy Policy.": "Ved å akseptere vilkårene og betingelsene for Scandic Friends, er jeg inneforstått med at mine personopplysninger vil bli behandlet i samsvar med Scandics personvernpolicy.", + "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.": "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.", "By paying with any of the payment methods available, I accept the terms for this booking and the general Terms & Conditions, and understand that Scandic will process my personal data for this booking in accordance with Scandic's Privacy policy. I also accept that Scandic require a valid credit card during my visit in case anything is left unpaid.": "Ved å betale med en av de tilgjengelige betalingsmetodene godtar jeg vilkårene og betingelsene for denne bestillingen og de generelle vilkårene, og forstår at Scandic vil behandle mine personopplysninger i forbindelse med denne bestillingen i henhold til Scandics personvernpolicy. Jeg aksepterer at Scandic krever et gyldig kredittkort under mitt besøk i tilfelle noe blir refundert.", "By signing up you accept the Scandic Friends Terms and Conditions. Your membership is valid until further notice, and you can terminate your membership at any time by sending an email to Scandic's customer service": "Ved å registrere deg godtar du Scandic Friends vilkår og betingelser. Medlemskapet ditt er gyldig inntil videre, og du kan si opp medlemskapet ditt når som helst ved å sende en e-post til Scandics kundeservice", "Campaign": "Kampanje", @@ -113,6 +116,7 @@ "Complete booking & go to payment": "Fullfør bestilling & gå til betaling", "Complete the booking": "Fullfør reservasjonen", "Contact information": "Kontaktinformasjon", + "Contact our memberservice": "Contact our memberservice", "Contact us": "Kontakt oss", "Continue": "Fortsette", "Could not find requested resource": "Kunne ikke finne den forespurte ressursen", @@ -126,11 +130,13 @@ "Current password": "Nåværende passord", "Customer service": "Kundeservice", "Date of Birth": "Fødselsdato", + "Date of birth not matching": "Date of birth not matching", "Day": "Dag", "Description": "Beskrivelse", "Destination": "Destinasjon", "Destinations & hotels": "Destinasjoner og hoteller", "Details": "Detaljer", + "Didn't receive a code? Resend code": "Didn't receive a code? Resend code", "Discard changes": "Forkaste endringer", "Discard unsaved changes?": "Forkaste endringer som ikke er lagret?", "Discover": "Oppdag", @@ -183,6 +189,7 @@ "Free parking": "Gratis parkering", "Free rebooking": "Gratis ombooking", "Friday": "Fredag", + "Friends with Benefits": "Friends with Benefits", "From": "Fra", "Garage": "Garasje", "Get inspired": "Bli inspirert", @@ -213,9 +220,11 @@ "I accept": "Jeg aksepterer", "I accept the terms and conditions": "Jeg aksepterer vilkårene", "I would like to get my booking confirmation via sms": "Jeg vil gjerne motta bekreftelsen av bestillingen min via sms", + "If you are not redirected automatically, please click here.": "If you are not redirected automatically, please click here.", "In adults bed": "i voksnes seng", "In crib": "i sprinkelseng", "In extra bed": "i ekstraseng", + "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.": "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.", "Included": "Inkludert", "IndoorPool": "Innendørs basseng", "Is there anything else you would like us to know before your arrival?": "Er det noe annet du vil at vi skal vite før ankomsten din?", @@ -243,6 +252,8 @@ "Level 7": "Nivå 7", "Level up to unlock": "Nivå opp for å låse opp", "Level {level}": "Nivå {level}", + "Link my accounts": "Link my accounts", + "Link your accounts": "Link your accounts", "Location": "Beliggenhet", "Locations": "Steder", "Log in": "Logg Inn", @@ -345,6 +356,7 @@ "Phone is required": "Telefon kreves", "Phone number": "Telefonnummer", "Please enter a valid phone number": "Vennligst oppgi et gyldig telefonnummer", + "Please enter the code sent to in order to confirm your account linking.": "Please enter the code sent to in order to confirm your account linking.", "Please note that this is mandatory, and that your card will only be charged in the event of a no-show.": "Vær oppmerksom på at dette er påkrevd, og at ditt kredittkort kun vil bli belastet i tilfelle av en no-show.", "Points": "Poeng", "Points being calculated": "Poeng beregnes", @@ -374,6 +386,8 @@ "Read more & book a table": "Read more & book a table", "Read more about the hotel": "Les mer om hotellet", "Read more about wellness & exercise": "Read more about wellness & exercise", + "Redirecting you to SAS": "Redirecting you to SAS", + "Redirecting you to my pages.": "Redirecting you to my pages.", "Reference #{bookingNr}": "Referanse #{bookingNr}", "Relax": "Slappe av", "Remove card from member profile": "Fjern kortet fra medlemsprofilen", @@ -453,6 +467,7 @@ "Terms and conditions": "Vilkår og betingelser", "Thank you": "Takk", "Thank you for booking with us! We look forward to welcoming you and hope you have a pleasant stay. If you have any questions or need to make changes to your reservation, please contact us.": "Takk for at du booket hos oss! Vi ser frem til å ønske deg velkommen og håper du får et hyggelig opphold. Hvis du har spørsmål eller trenger å gjøre endringer i bestillingen din, vennligst kontakt oss.", + "The code you’ve entered is incorrect.": "The code you’ve entered is incorrect.", "The new price is": "Den nye prisen er", "The price has increased": "Prisen er steget", "The price has increased since you selected your room.": "Prisen er steget, etter at du har valgt rommet.", @@ -462,6 +477,7 @@ "Things nearby {hotelName}": "Ting i nærheten av {hotelName}", "This room is equipped with": "Dette rommet er utstyrt med", "This room is not available": "Dette rommet er ikke tilgjengelig", + "This verifcation is needed for additional security.": "This verifcation is needed for additional security.", "Thursday": "Torsdag", "Times": "Tider", "To get the member price {price}, log in or join when completing the booking.": "For å få medlemsprisen {price}, logg inn eller bli med når du fullfører bestillingen.", @@ -483,16 +499,22 @@ "User information": "Brukerinformasjon", "VAT {vat}%": "mva {vat}%", "Valid through {expirationDate}": "Gyldig til og med {expirationDate}", + "Verification code": "Verification code", "View as list": "Vis som liste", "View as map": "Vis som kart", + "View your account": "View your account", "View your booking": "Se din bestilling", "Visiting address": "Besøksadresse", "Voucher": "Voucher", "We could not add a card right now, please try again later.": "Vi kunne ikke legge til et kort akkurat nå. Prøv igjen senere.", + "We could not connect your accounts": "We could not connect your accounts", + "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.": "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.", "We couldn't find a matching location for your search.": "Vi finner ikke et sted som samsvarer for søket ditt.", "We had an issue processing your booking. Please try again. No charges have been made.": "Vi hadde et problem med å behandle din bestilling. Vær så snill å prøv igjen. Ingen gebyrer er blevet belastet.", "We have a special gift waiting for you!": "Vi har en spesiell gave som venter på deg!", "We look forward to your visit!": "Vi ser frem til ditt besøk!", + "We require this additional information in order to match your Scandic account with your EuroBonus account.": "We require this additional information in order to match your Scandic account with your EuroBonus account.", + "We successfully connected your accounts!": "We successfully connected your accounts!", "We're sorry": "Vi beklager", "Wednesday": "Onsdag", "Weekday": "Ukedag", @@ -521,8 +543,10 @@ "You have no previous stays.": "Du har ingen tidligere opphold.", "You have no upcoming stays.": "Du har ingen kommende opphold.", "You have now cancelled your payment.": "Du har nå annullerer din betaling.", + "You must accept the terms and conditions": "You must accept the terms and conditions", "You'll find all your gifts in 'My benefits'": "Du finner alle gavene dine i 'Mine fordeler'", "Your Challenges Conquer & Earn!": "Dine utfordringer Erobre og tjen!", + "Your accounts are connected": "Your accounts are connected", "Your booking(s) is confirmed but we could not verify your membership. If you have booked with a member discount, you'll either need to present your existing membership number upon check-in, become a member or pay the price difference at the hotel. Signing up is preferably done online before the stay.": "Din bestilling er bekreftet, men vi kunne ikke verifisere medlemskapet ditt. Hvis du har booke ut med et medlemsrabatt, må du enten presentere eksisterende medlemsnummer ved check-in, bli medlem eller betale prisdifferansen ved hotellet. Registrering er foretrukket gjort online før oppholdet.", "Your card was successfully removed!": "Kortet ditt ble fjernet!", "Your card was successfully saved!": "Kortet ditt ble lagret!", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index 1d9c1f3c6..c5e2e1df1 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -14,6 +14,7 @@ "Accessibility": "Tillgänglighet", "Accessibility at {hotel}": "Tillgänglighet på {hotel}", "Accessible Room": "Tillgänglighetsrum", + "Accounts are already linked": "Accounts are already linked", "Active": "Aktiv", "Activities": "Aktiviteter", "Add code": "Lägg till kod", @@ -57,6 +58,7 @@ "Bed type": "Sängtyp", "Bike friendly": "Cykelvänligt", "Birth date": "Födelsedatum", + "Birth date is required": "Birth date is required", "Book": "Boka", "Book a table online": "Boka ett bord online", "Book parking": "Boka parkering", @@ -78,6 +80,7 @@ "Bus terminal": "Bussterminal", "Business": "Business", "By accepting the Terms and Conditions for Scandic Friends I understand that my personal data will be processed in accordance with Scandic's Privacy Policy.": "Genom att acceptera villkoren för Scandic Friends förstår jag att mina personuppgifter kommer att behandlas i enlighet med Scandics Integritetspolicy.", + "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.": "By linking your accounts you accept the Scandic Friends & SAS Terms and Conditions. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.", "By paying with any of the payment methods available, I accept the terms for this booking and the general Terms & Conditions, and understand that Scandic will process my personal data for this booking in accordance with Scandic's Privacy policy. I also accept that Scandic require a valid credit card during my visit in case anything is left unpaid.": "Genom att betala med någon av de tillgängliga betalningsmetoderna accepterar jag villkoren för denna bokning och de generella Villkoren och villkoren, och förstår att Scandic kommer att behandla min personliga data i samband med denna bokning i enlighet med Scandics integritetspolicy. Jag accepterar att Scandic kräver ett giltigt kreditkort under min besök i fall att något är tillbaka betalt.", "By signing up you accept the Scandic Friends Terms and Conditions. Your membership is valid until further notice, and you can terminate your membership at any time by sending an email to Scandic's customer service": "Genom att registrera dig accepterar du Scandic Friends Användarvillkor. Ditt medlemskap gäller tills vidare och du kan när som helst säga upp ditt medlemskap genom att skicka ett mejl till Scandics kundtjänst", "Campaign": "Kampanj", @@ -113,6 +116,7 @@ "Complete booking & go to payment": "Fullför bokning & gå till betalning", "Complete the booking": "Slutför bokningen", "Contact information": "Kontaktinformation", + "Contact our memberservice": "Contact our memberservice", "Contact us": "Kontakta oss", "Continue": "Fortsätt", "Could not find requested resource": "Det gick inte att hitta den begärda resursen", @@ -126,11 +130,13 @@ "Current password": "Nuvarande lösenord", "Customer service": "Kundservice", "Date of Birth": "Födelsedatum", + "Date of birth not matching": "Date of birth not matching", "Day": "Dag", "Description": "Beskrivning", "Destination": "Destination", "Destinations & hotels": "Destinationer & hotell", "Details": "Detaljer", + "Didn't receive a code? Resend code": "Didn't receive a code? Resend code", "Discard changes": "Ignorera ändringar", "Discard unsaved changes?": "Vill du ignorera ändringar som inte har sparats?", "Discover": "Upptäck", @@ -183,6 +189,7 @@ "Free parking": "Gratis parkering", "Free rebooking": "Fri ombokning", "Friday": "Fredag", + "Friends with Benefits": "Friends with Benefits", "From": "Från", "Garage": "Garage", "Get inspired": "Bli inspirerad", @@ -213,9 +220,11 @@ "I accept": "Jag accepterar", "I accept the terms and conditions": "Jag accepterar villkoren", "I would like to get my booking confirmation via sms": "Jag vill få min bokningsbekräftelse via sms", + "If you are not redirected automatically, please click here.": "If you are not redirected automatically, please click here.", "In adults bed": "I vuxens säng", "In crib": "I spjälsäng", "In extra bed": "Egen sängplats", + "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.": "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.", "Included": "Inkluderad", "IndoorPool": "Inomhuspool", "Is there anything else you would like us to know before your arrival?": "Är det något mer du vill att vi ska veta innan din ankomst?", @@ -243,6 +252,8 @@ "Level 7": "Nivå 7", "Level up to unlock": "Levla upp för att låsa upp", "Level {level}": "Nivå {level}", + "Link my accounts": "Link my accounts", + "Link your accounts": "Link your accounts", "Location": "Plats", "Locations": "Platser", "Log in": "Logga in", @@ -345,6 +356,7 @@ "Phone is required": "Telefonnummer är obligatorisk", "Phone number": "Telefonnummer", "Please enter a valid phone number": "Var vänlig och ange ett giltigt telefonnummer", + "Please enter the code sent to in order to confirm your account linking.": "Please enter the code sent to in order to confirm your account linking.", "Please note that this is mandatory, and that your card will only be charged in the event of a no-show.": "Vänligen notera att detta är obligatoriskt, och att ditt kreditkort endast debiteras i händelse av en no-show.", "Points": "Poäng", "Points being calculated": "Poäng beräknas", @@ -374,6 +386,8 @@ "Read more & book a table": "Read more & book a table", "Read more about the hotel": "Läs mer om hotellet", "Read more about wellness & exercise": "Read more about wellness & exercise", + "Redirecting you to SAS": "Redirecting you to SAS", + "Redirecting you to my pages.": "Redirecting you to my pages.", "Reference #{bookingNr}": "Referens #{bookingNr}", "Relax": "Koppla av", "Remove card from member profile": "Ta bort kortet från medlemsprofilen", @@ -453,6 +467,7 @@ "Terms and conditions": "Allmänna villkor", "Thank you": "Tack", "Thank you for booking with us! We look forward to welcoming you and hope you have a pleasant stay. If you have any questions or need to make changes to your reservation, please contact us.": "Tack för att du bokar hos oss! Vi ser fram emot att välkomna dig och hoppas att du får en trevlig vistelse. Om du har några frågor eller behöver göra ändringar i din bokning, vänligen kontakta oss.", + "The code you’ve entered is incorrect.": "The code you’ve entered is incorrect.", "The new price is": "Det nya priset är", "The price has increased": "Priset har ökat", "The price has increased since you selected your room.": "Priset har ökat sedan du valde ditt rum.", @@ -462,6 +477,7 @@ "Things nearby {hotelName}": "Saker i närheten av {hotelName}", "This room is equipped with": "Detta rum är utrustat med", "This room is not available": "Detta rum är inte tillgängligt", + "This verifcation is needed for additional security.": "This verifcation is needed for additional security.", "Thursday": "Torsdag", "Times": "Tider", "To get the member price {price}, log in or join when completing the booking.": "För att få medlemsprisen {price}, logga in eller bli medlem när du slutför bokningen.", @@ -483,16 +499,22 @@ "User information": "Användarinformation", "VAT {vat}%": "Moms {vat}%", "Valid through {expirationDate}": "Gäller till och med {expirationDate}", + "Verification code": "Verification code", "View as list": "Visa som lista", "View as map": "Visa som karta", + "View your account": "View your account", "View your booking": "Visa din bokning", "Visiting address": "Besöksadress", "Voucher": "Kupong", "We could not add a card right now, please try again later.": "Vi kunde inte lägga till ett kort just nu, vänligen försök igen senare.", + "We could not connect your accounts": "We could not connect your accounts", + "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.": "We could not connect your accounts to give you access. Please contact us and we’ll help you resolve this issue.", "We couldn't find a matching location for your search.": "Vi kunde inte hitta en plats som matchade din sökning.", "We had an issue processing your booking. Please try again. No charges have been made.": "Vi hade ett problem med att bearbeta din bokning. Vänligen försök igen. Inga avgifter har debiterats.", "We have a special gift waiting for you!": "Vi har en speciell present som väntar på dig!", "We look forward to your visit!": "Vi ser fram emot ditt besök!", + "We require this additional information in order to match your Scandic account with your EuroBonus account.": "We require this additional information in order to match your Scandic account with your EuroBonus account.", + "We successfully connected your accounts!": "We successfully connected your accounts!", "We're sorry": "Vi beklagar", "Wednesday": "Onsdag", "Weekday": "Vardag", @@ -521,8 +543,10 @@ "You have no previous stays.": "Du har inga tidigare vistelser.", "You have no upcoming stays.": "Du har inga planerade resor.", "You have now cancelled your payment.": "Du har nu avbrutit din betalning.", + "You must accept the terms and conditions": "You must accept the terms and conditions", "You'll find all your gifts in 'My benefits'": "Du hittar alla dina gåvor i 'Mina förmåner'", "Your Challenges Conquer & Earn!": "Dina utmaningar Erövra och tjäna!", + "Your accounts are connected": "Your accounts are connected", "Your booking(s) is confirmed but we could not verify your membership. If you have booked with a member discount, you'll either need to present your existing membership number upon check-in, become a member or pay the price difference at the hotel. Signing up is preferably done online before the stay.": "Din bokning är bekräftad, men vi kunde inte verifiera ditt medlemskap. Om du har bokat med ett medlemsrabatt måste du antingen presentera ditt befintliga medlemsnummer vid check-in, bli medlem eller betala prisdifferensen vid hotell. Registrering är föredragen gjord online före vistelsen.", "Your card was successfully removed!": "Ditt kort har tagits bort!", "Your card was successfully saved!": "Ditt kort har sparats!", diff --git a/middleware.ts b/middleware.ts index 503cd22cf..cad34e08b 100644 --- a/middleware.ts +++ b/middleware.ts @@ -12,6 +12,7 @@ import * as currentWebLogout from "@/middlewares/currentWebLogout" import * as dateFormat from "@/middlewares/dateFormat" import * as handleAuth from "@/middlewares/handleAuth" import * as myPages from "@/middlewares/myPages" +import * as sasXScandic from "@/middlewares/sasXScandic" import { getDefaultRequestHeaders } from "@/middlewares/utils" import * as webView from "@/middlewares/webView" import { findLang } from "@/utils/languages" @@ -55,6 +56,7 @@ export const middleware: NextMiddleware = async (request, event) => { webView, dateFormat, bookingFlow, + sasXScandic, cmsContent, ] diff --git a/middlewares/sasXScandic.ts b/middlewares/sasXScandic.ts new file mode 100644 index 000000000..ba093e249 --- /dev/null +++ b/middlewares/sasXScandic.ts @@ -0,0 +1,22 @@ +import { type NextMiddleware,NextResponse } from "next/server" + +import { Lang } from "@/constants/languages" + +import { getDefaultRequestHeaders } from "./utils" + +import type { MiddlewareMatcher } from "@/types/middleware" + +export const middleware: NextMiddleware = async (request) => { + const headers = getDefaultRequestHeaders(request) + return NextResponse.next({ + request: { + headers, + }, + }) +} + +export const matcher: MiddlewareMatcher = (request) => { + return !!request.nextUrl.pathname.match( + new RegExp(`^/(${Object.values(Lang).join("|")})/(sas-x-scandic)/.+`) + ) +} diff --git a/package-lock.json b/package-lock.json index 8ec681ea8..9e76ae9a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "@sentry/nextjs": "^8.41.0", "@t3-oss/env-nextjs": "^0.9.2", "@tanstack/react-query": "^5.28.6", + "@tanstack/react-query-devtools": "^5.64.2", "@tanstack/react-table": "^8.20.5", "@trpc/client": "^11.0.0-rc.467", "@trpc/react-query": "^11.0.0-rc.467", @@ -44,6 +45,7 @@ "graphql-tag": "^2.12.6", "ics": "^3.8.1", "immer": "10.1.1", + "input-otp": "^1.4.2", "json-stable-stringify-without-jsonify": "^1.0.1", "libphonenumber-js": "^1.10.60", "nanoid": "^5.0.9", @@ -61,6 +63,7 @@ "sonner": "^1.7.0", "superjson": "^2.2.1", "usehooks-ts": "3.1.0", + "uuid": "^11.0.5", "zod": "^3.22.4", "zustand": "^4.5.2" }, @@ -7655,9 +7658,19 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.51.9", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.51.9.tgz", - "integrity": "sha512-HsAwaY5J19MD18ykZDS3aVVh+bAt0i7m6uQlFC2b77DLV9djo+xEN7MWQAQQTR8IM+7r/zbozTQ7P0xr0bHuew==", + "version": "5.64.2", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.64.2.tgz", + "integrity": "sha512-hdO8SZpWXoADNTWXV9We8CwTkXU88OVWRBcsiFrk7xJQnhm6WRlweDzMD+uH+GnuieTBVSML6xFa17C2cNV8+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-devtools": { + "version": "5.64.2", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.64.2.tgz", + "integrity": "sha512-3DautR5UpVZdk/qNIhioZVF7g8fdQZ1U98sBEEk4Tzz3tihSBNMPgwlP40nzgbPEDBIrn/j/oyyvNBVSo083Vw==", "license": "MIT", "funding": { "type": "github", @@ -7665,19 +7678,36 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.51.11", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.51.11.tgz", - "integrity": "sha512-4Kq2x0XpDlpvSnaLG+8pHNH60zEc3mBvb3B2tOMDjcPCi/o+Du3p/9qpPLwJOTliVxxPJAP27fuIhLrsRdCr7A==", + "version": "5.64.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.64.2.tgz", + "integrity": "sha512-3pakNscZNm8KJkxmovvtZ4RaXLyiYYobwleTMvpIGUoKRa8j8VlrQKNl5W8VUEfVfZKkikvXVddLuWMbcSCA1Q==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.51.9" + "@tanstack/query-core": "5.64.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "react": "^18.0.0" + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.64.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.64.2.tgz", + "integrity": "sha512-+ZjJVnPzc8BUV/Eklu2k9T/IAyAyvwoCHqOaOrk2sbU33LFhM52BpX4eyENXn0bx5LwV3DJZgEQlIzucoemfGQ==", + "license": "MIT", + "dependencies": { + "@tanstack/query-devtools": "5.64.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.64.2", + "react": "^18 || ^19" } }, "node_modules/@tanstack/react-table": { @@ -14040,6 +14070,16 @@ "node": ">=10" } }, + "node_modules/input-otp": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.2.tgz", + "integrity": "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -22137,6 +22177,19 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz", + "integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", diff --git a/package.json b/package.json index 45a3c811d..58e40fb29 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "@sentry/nextjs": "^8.41.0", "@t3-oss/env-nextjs": "^0.9.2", "@tanstack/react-query": "^5.28.6", + "@tanstack/react-query-devtools": "^5.64.2", "@tanstack/react-table": "^8.20.5", "@trpc/client": "^11.0.0-rc.467", "@trpc/react-query": "^11.0.0-rc.467", @@ -59,6 +60,7 @@ "graphql-tag": "^2.12.6", "ics": "^3.8.1", "immer": "10.1.1", + "input-otp": "^1.4.2", "json-stable-stringify-without-jsonify": "^1.0.1", "libphonenumber-js": "^1.10.60", "nanoid": "^5.0.9", @@ -76,6 +78,7 @@ "sonner": "^1.7.0", "superjson": "^2.2.1", "usehooks-ts": "3.1.0", + "uuid": "^11.0.5", "zod": "^3.22.4", "zustand": "^4.5.2" }, diff --git a/public/_static/img/partner/sas/sas-campaign-logo.png b/public/_static/img/partner/sas/sas-campaign-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d86aab939c6f2687694d32c243be203eeeb76924 GIT binary patch literal 11015 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

>g}XfzfUOgXMq|MqoL_1UpI?7g1Lp})eT)$0NC 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 literal 0 HcmV?d00001 diff --git a/public/_static/img/partner/sas/sas_x_scandic_airplane_window_background.jpg b/public/_static/img/partner/sas/sas_x_scandic_airplane_window_background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d26bcc51d23662a627eb6548e44b57d0e68b97b2 GIT binary patch literal 163407 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

HeP@}pK33lYx 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 z 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

OT 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 F|JfpSvv2?a literal 0 HcmV?d00001 diff --git a/public/_static/img/scandic-loyalty-time.svg b/public/_static/img/scandic-loyalty-time.svg new file mode 100644 index 000000000..77394ef3f --- /dev/null +++ b/public/_static/img/scandic-loyalty-time.svg @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/server/context.ts b/server/context.ts index f33d6b1c9..ddf7f762f 100644 --- a/server/context.ts +++ b/server/context.ts @@ -2,10 +2,10 @@ import { cookies, headers } from "next/headers" import { type Session } from "next-auth" import { cache } from "react" -import { Lang } from "@/constants/languages" - import { auth } from "@/auth" +import type { Lang } from "@/constants/languages" + typeof auth type CreateContextOptions = { diff --git a/server/index.ts b/server/index.ts index 6f41f4391..676958d9f 100644 --- a/server/index.ts +++ b/server/index.ts @@ -2,6 +2,7 @@ import { bookingRouter } from "./routers/booking" import { contentstackRouter } from "./routers/contentstack" import { hotelsRouter } from "./routers/hotels" +import { partnerRouter } from "./routers/partners" import { userRouter } from "./routers/user" import { router } from "./trpc" @@ -10,6 +11,7 @@ export const appRouter = router({ contentstack: contentstackRouter, hotel: hotelsRouter, user: userRouter, + partner: partnerRouter, }) export type AppRouter = typeof appRouter diff --git a/server/routers/contentstack/reward/utils.ts b/server/routers/contentstack/reward/utils.ts index 2b5c746a8..f8cd7ffc3 100644 --- a/server/routers/contentstack/reward/utils.ts +++ b/server/routers/contentstack/reward/utils.ts @@ -11,12 +11,13 @@ import { notFound } from "@/server/errors/trpc" import { generateLoyaltyConfigTag } from "@/utils/generateTag" import { -type - CmsRewardsResponse,type - CmsRewardsWithRedeemResponse, validateApiAllTiersSchema, + type CmsRewardsResponse, + type CmsRewardsWithRedeemResponse, + validateApiAllTiersSchema, validateApiTierRewardsSchema, validateCmsRewardsSchema, - validateCmsRewardsWithRedeemSchema} from "./output" + validateCmsRewardsWithRedeemSchema, +} from "./output" import type { Lang } from "@/constants/languages" diff --git a/server/routers/partners/index.ts b/server/routers/partners/index.ts new file mode 100644 index 000000000..3f26ae6a3 --- /dev/null +++ b/server/routers/partners/index.ts @@ -0,0 +1,5 @@ +import { router } from "@/server/trpc" + +import { sasRouter } from "./sas" + +export const partnerRouter = router({ sas: sasRouter }) diff --git a/server/routers/partners/sas/getSasToken.ts b/server/routers/partners/sas/getSasToken.ts new file mode 100644 index 000000000..b6de657a5 --- /dev/null +++ b/server/routers/partners/sas/getSasToken.ts @@ -0,0 +1,11 @@ +import { cookies } from "next/headers" + +import { SAS_TOKEN_STORAGE_KEY } from "@/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/sasUtils" + +export function getSasToken() { + const cookieStore = cookies() + const tokenCookie = cookieStore.get(SAS_TOKEN_STORAGE_KEY) + const sasAuthToken = tokenCookie?.value + + return sasAuthToken +} diff --git a/server/routers/partners/sas/index.ts b/server/routers/partners/sas/index.ts new file mode 100644 index 000000000..702acd694 --- /dev/null +++ b/server/routers/partners/sas/index.ts @@ -0,0 +1,7 @@ +import { router } from "@/server/trpc" + +import { requestOtp } from "./otp/request/requestOtp" +import { verifyOtp } from "./otp/verify/verifyOtp" +import { linkAccount } from "./linkAccount" + +export const sasRouter = router({ verifyOtp, requestOtp, linkAccount }) diff --git a/server/routers/partners/sas/linkAccount.ts b/server/routers/partners/sas/linkAccount.ts new file mode 100644 index 000000000..59308e53d --- /dev/null +++ b/server/routers/partners/sas/linkAccount.ts @@ -0,0 +1,28 @@ +import { z } from "zod" + +import { protectedProcedure } from "@/server/trpc" + +import { getSasToken } from "./getSasToken" + +const outputSchema = z.object({ + linkingState: z.enum(["linked"]), +}) + +export const linkAccount = protectedProcedure + .output(outputSchema) + .mutation(async function ({ ctx, input }) { + const sasAuthToken = getSasToken() + + console.log("[SAS] link account") + await timeout(1000) + //TODO: Call actual API here + console.log("[SAS] link account done") + + return { + linkingState: "linked", + } + }) + +function timeout(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)) +} diff --git a/server/routers/partners/sas/otp/constants.ts b/server/routers/partners/sas/otp/constants.ts new file mode 100644 index 000000000..40591d967 --- /dev/null +++ b/server/routers/partners/sas/otp/constants.ts @@ -0,0 +1,2 @@ +export const SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME = + "sas-x-scandic-request-otp-state" diff --git a/server/routers/partners/sas/otp/getOTPState.ts b/server/routers/partners/sas/otp/getOTPState.ts new file mode 100644 index 000000000..fdf486afc --- /dev/null +++ b/server/routers/partners/sas/otp/getOTPState.ts @@ -0,0 +1,17 @@ +import { cookies } from "next/headers" +import { z } from "zod" + +import { SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME } from "./constants" + +const otpStateSchema = z.object({ + referenceId: z.string().uuid(), + databaseUUID: z.string().uuid(), +}) + +export type OtpState = z.infer + +export function getOTPState() { + const otpState = cookies().get(SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME) + + return otpStateSchema.parse(JSON.parse(otpState?.value ?? "{}")) +} diff --git a/server/routers/partners/sas/otp/request/requestOtp.ts b/server/routers/partners/sas/otp/request/requestOtp.ts new file mode 100644 index 000000000..be0434001 --- /dev/null +++ b/server/routers/partners/sas/otp/request/requestOtp.ts @@ -0,0 +1,116 @@ +import { TRPCError } from "@trpc/server" +import { cookies } from "next/headers" +import { v4 as uuidv4 } from "uuid" +import { z } from "zod" + +import { env } from "@/env/server" +import { protectedProcedure } from "@/server/trpc" + +import { getSasToken } from "../../getSasToken" +import { SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME } from "../constants" +import { + parseSASRequestOtpError, + type RequestOtpGeneralError, +} from "./requestOtpError" + +import type { OtpState } from "../getOTPState" + +const inputSchema = z.object({}) + +const outputSchema = z.object({ + status: z.string(), + referenceId: z.string().uuid(), + databaseUUID: z.string().uuid(), + otpExpiration: z.number(), + otpReceiver: z.string(), +}) + +export const requestOtp = protectedProcedure + .input(inputSchema) + .output(outputSchema) + .mutation(async function ({ ctx, input }) { + const sasAuthToken = getSasToken() + + if (!sasAuthToken) { + // TODO: Should we verify that the SAS token isn't expired? + throw createError("AUTH_TOKEN_NOT_FOUND") + } + + const tokenResponse = await fetchRequestOtp({ sasAuthToken }) + console.log( + "[SAS] requestOtp", + tokenResponse.status, + tokenResponse.statusText + ) + if (!tokenResponse.ok) { + const errorBody = await tokenResponse.json() + console.error("[SAS] requestOtp error", errorBody) + throw createError(errorBody) + } + + const parseResult = outputSchema.safeParse(await tokenResponse.json()) + if (!parseResult.success) { + throw createError(parseResult.error) + } + + setSASOtpCookie(parseResult.data) + + return parseResult.data + }) + +function createError( + errorBody: + | { + status: string + error: string + errorCode: number + databaseUUID: string + } + | Error + | RequestOtpGeneralError +): TRPCError { + const errorInfo = parseSASRequestOtpError(errorBody) + console.error("[SAS] createError", errorInfo) + return new TRPCError({ + code: "BAD_REQUEST", + cause: errorInfo, + }) +} + +async function fetchRequestOtp({ sasAuthToken }: { sasAuthToken: string }) { + const endpoint = `${env.SAS_API_ENDPOINT}/api/scandic-partnership/customer/send-otp` + + console.log("[SAS]: Requesting OTP") + + return await fetch(endpoint, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Ocp-Apim-Subscription-Key": env.SAS_OCP_APIM, + Authorization: `Bearer ${sasAuthToken}`, + }, + body: JSON.stringify({ + referenceId: uuidv4(), + }), + }) +} + +function setSASOtpCookie({ + referenceId, + databaseUUID, +}: { + referenceId: string + databaseUUID: string +}) { + cookies().set( + SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME, + JSON.stringify({ + referenceId: referenceId, + databaseUUID: databaseUUID, + } satisfies OtpState), + { + httpOnly: true, + maxAge: 3600, + } + ) +} diff --git a/server/routers/partners/sas/otp/request/requestOtpError.test.ts b/server/routers/partners/sas/otp/request/requestOtpError.test.ts new file mode 100644 index 000000000..5bac6bcca --- /dev/null +++ b/server/routers/partners/sas/otp/request/requestOtpError.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from "@jest/globals" + +import { parseSASRequestOtpError } from "./requestOtpError" + +describe("requestOtpError", () => { + it("parses error with invalid error code", () => { + const error = { + status: "status", + error: "error", + errorCode: "a", + databaseUUID: "9ffefefe-df0e-4229-9792-5ed31bef1db4", + } + + const actual = parseSASRequestOtpError({ + status: "status", + error: "error", + errorCode: "a" as unknown as number, + databaseUUID: "9ffefefe-df0e-4229-9792-5ed31bef1db4", + } as any) + expect(actual).toEqual({ + errorCode: "UNKNOWN", + }) + }) + + it("parses error as TOO_MANY_REQUESTS error code", () => { + const actual = parseSASRequestOtpError({ + status: "status", + error: "error", + errorCode: 10, + databaseUUID: "9ffefefe-df0e-4229-9792-5ed31bef1db4", + otpExpiration: "2021-09-01T00:00:00Z", + }) + expect(actual).toEqual({ + errorCode: "TOO_MANY_REQUESTS", + }) + }) +}) diff --git a/server/routers/partners/sas/otp/request/requestOtpError.ts b/server/routers/partners/sas/otp/request/requestOtpError.ts new file mode 100644 index 000000000..8f1621c5f --- /dev/null +++ b/server/routers/partners/sas/otp/request/requestOtpError.ts @@ -0,0 +1,61 @@ +import { z } from "zod" + +export type RequestOtpResponseError = "TOO_MANY_REQUESTS" | "UNKNOWN" + +const requestOtpGeneralError = z.enum([ + "AUTH_TOKEN_EXPIRED", + "AUTH_TOKEN_NOT_FOUND", + "UNKNOWN", +]) +export type RequestOtpGeneralError = z.infer + +export type RequestOtpError = { + errorCode: RequestOtpResponseError | RequestOtpGeneralError +} +export function parseSASRequestOtpError( + error: SasOtpRequestError | {} +): RequestOtpError { + const parseResult = sasOtpRequestErrorSchema.safeParse(error) + if (!parseResult.success) { + const generalErrorResult = requestOtpGeneralError.safeParse(error) + if (!generalErrorResult.success) { + return { + errorCode: "UNKNOWN", + } + } + + return { + errorCode: generalErrorResult.data, + } + } + + return { + errorCode: getErrorCodeByNumber(parseResult.data.errorCode), + } +} + +const SAS_REQUEST_OTP_ERROR_CODES: { + [key in Exclude]: number +} = { + TOO_MANY_REQUESTS: 10, +} + +const getErrorCodeByNumber = (number: number): RequestOtpResponseError => { + const v = + Object.entries(SAS_REQUEST_OTP_ERROR_CODES).find( + ([_, value]) => value === number + )?.[0] ?? "UNKNOWN" + + console.log("[SAS] getErrorCodeByNumber", number, v) + return v as RequestOtpResponseError +} + +const sasOtpRequestErrorSchema = z.object({ + status: z.string(), + otpExpiration: z.string().datetime(), + error: z.string(), + errorCode: z.number(), + databaseUUID: z.string().uuid(), +}) + +export type SasOtpRequestError = z.infer diff --git a/server/routers/partners/sas/otp/verify/verifyOtp.ts b/server/routers/partners/sas/otp/verify/verifyOtp.ts new file mode 100644 index 000000000..91e7e372e --- /dev/null +++ b/server/routers/partners/sas/otp/verify/verifyOtp.ts @@ -0,0 +1,96 @@ +import { TRPCError } from "@trpc/server" +import { cookies } from "next/headers" +import { z } from "zod" + +import { env } from "@/env/server" +import { protectedProcedure } from "@/server/trpc" + +import { getSasToken } from "../../getSasToken" +import { getOTPState } from "../getOTPState" +import { + parseSASVerifyOtpError, + type VerifyOtpGeneralError, +} from "./verifyOtpError" + +const inputSchema = z.object({ + otp: z.string(), +}) + +const outputSchema = z.object({ + status: z.string(), // TODO: Change to enum + referenceId: z.string().uuid(), + databaseUUID: z.string().uuid().optional(), +}) + +export const verifyOtp = protectedProcedure + .input(inputSchema) + .output(outputSchema) + .mutation(async function ({ ctx, input }) { + const sasAuthToken = getSasToken() + + if (!sasAuthToken) { + // TODO: Should we verify that the SAS token isn't expired? + throw createError("AUTH_TOKEN_NOT_FOUND") + } + + const verifyResponse = await fetchVerifyOtp(input) + console.log( + "[SAS] verifyOTP", + verifyResponse.status, + verifyResponse.statusText + ) + if (!verifyResponse.ok) { + const errorBody = await verifyResponse.json() + console.error("[SAS] verifyOTP error", errorBody) + throw createError(errorBody) + } + + console.log("[SAS] verifyOTP success") + const verifyData = await verifyResponse.json() + console.log("[SAS] verifyOTP data", verifyData) + const response = outputSchema.parse(verifyData) + console.log("[SAS] verifyOTP responding", response) + + return response + }) + +async function fetchVerifyOtp(input: z.infer) { + const sasAuthToken = getSasToken() + const { referenceId, databaseUUID } = getOTPState() + + return await fetch( + `${env.SAS_API_ENDPOINT}/api/scandic-partnership/customer/verify-otp`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + "Ocp-Apim-Subscription-Key": env.SAS_OCP_APIM, + Authorization: `Bearer ${sasAuthToken}`, + }, + body: JSON.stringify({ + referenceId: referenceId, + otpCode: input.otp, + databaseUUID: databaseUUID, + }), + } + ) +} + +function createError( + errorBody: + | { + status: string + error: string + errorCode: number + databaseUUID: string + } + | Error + | VerifyOtpGeneralError +): TRPCError { + const errorInfo = parseSASVerifyOtpError(errorBody) + + return new TRPCError({ + code: "BAD_REQUEST", + cause: errorInfo, + }) +} diff --git a/server/routers/partners/sas/otp/verify/verifyOtpError.test.ts b/server/routers/partners/sas/otp/verify/verifyOtpError.test.ts new file mode 100644 index 000000000..92f4caafb --- /dev/null +++ b/server/routers/partners/sas/otp/verify/verifyOtpError.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from "@jest/globals" + +import { parseSASVerifyOtpError } from "./verifyOtpError" + +describe("verifyOtpError", () => { + it("parses error with invalid error code", () => { + const error = { + status: "status", + error: "error", + errorCode: "a", + databaseUUID: "9ffefefe-df0e-4229-9792-5ed31bef1db4", + } + + const actual = parseSASVerifyOtpError({ + status: "status", + error: "error", + errorCode: "a" as unknown as number, + databaseUUID: "9ffefefe-df0e-4229-9792-5ed31bef1db4", + } as any) + expect(actual).toEqual({ + errorCode: "UNKNOWN", + }) + }) +}) diff --git a/server/routers/partners/sas/otp/verify/verifyOtpError.ts b/server/routers/partners/sas/otp/verify/verifyOtpError.ts new file mode 100644 index 000000000..c2d25dd84 --- /dev/null +++ b/server/routers/partners/sas/otp/verify/verifyOtpError.ts @@ -0,0 +1,57 @@ +import { z } from "zod" + +export type VerifyOtpResponseError = "OTP_EXPIRED" | "WRONG_OTP" | "UNKNOWN" + +const VerifyOtpGeneralError = z.enum(["AUTH_TOKEN_NOT_FOUND", "UNKNOWN"]) +export type VerifyOtpGeneralError = z.infer + +export type VerifyOtpError = { + errorCode: VerifyOtpResponseError | VerifyOtpGeneralError +} +export function parseSASVerifyOtpError( + error: SasOtpVerifyError | {} +): VerifyOtpError { + const parseResult = sasOtpVerifyErrorSchema.safeParse(error) + if (!parseResult.success) { + const generalErrorResult = VerifyOtpGeneralError.safeParse(error) + if (!generalErrorResult.success) { + return { + errorCode: "UNKNOWN", + } + } + + return { + errorCode: generalErrorResult.data, + } + } + + return { + errorCode: getErrorCodeByNumber(parseResult.data.errorCode), + } +} + +const SAS_VERIFY_OTP_ERROR_CODES: { + [key in Exclude]: number +} = { + OTP_EXPIRED: 1, + WRONG_OTP: 2, +} + +const getErrorCodeByNumber = (number: number): VerifyOtpResponseError => { + const v = + Object.entries(SAS_VERIFY_OTP_ERROR_CODES).find( + ([_, value]) => value === number + )?.[0] ?? "UNKNOWN" + + return v as VerifyOtpResponseError +} + +const sasOtpVerifyErrorSchema = z.object({ + status: z.string(), + otpExpiration: z.string().datetime(), + error: z.string(), + errorCode: z.number(), + databaseUUID: z.string().uuid(), +}) + +export type SasOtpVerifyError = z.infer diff --git a/server/trpc.ts b/server/trpc.ts index 49f1fbcce..5751d929b 100644 --- a/server/trpc.ts +++ b/server/trpc.ts @@ -30,6 +30,10 @@ const t = initTRPC ...shape, data: { ...shape.data, + cause: + error.cause instanceof ZodError + ? undefined + : JSON.parse(JSON.stringify(error.cause)), zodError: error.cause instanceof ZodError ? error.cause.flatten() : null, }, diff --git a/types/components/hotelLogo.ts b/types/components/hotelLogo.ts index 8f19490a6..616ee3703 100644 --- a/types/components/hotelLogo.ts +++ b/types/components/hotelLogo.ts @@ -1,4 +1,4 @@ -import { Hotel } from "@/types/hotel" +import type { Hotel } from "@/types/hotel" export type HotelLogoProps = { hotelId: Hotel["operaId"] diff --git a/types/components/hotelReservation/selectHotel/hotelCardProps.ts b/types/components/hotelReservation/selectHotel/hotelCardProps.ts index 9880ecbfc..5aa4e1094 100644 --- a/types/components/hotelReservation/selectHotel/hotelCardProps.ts +++ b/types/components/hotelReservation/selectHotel/hotelCardProps.ts @@ -1,7 +1,7 @@ import { -type - HotelCardListingTypeEnum, type HotelData} from "./hotelCardListingProps" - + type HotelCardListingTypeEnum, + type HotelData, +} from "./hotelCardListingProps" export type HotelCardProps = { hotel: HotelData