Merged in feat/sw-3192-no-user (pull request #2680)
feat(SW-3192): Checks if user exists, otherwise logout and show error * feat(SW-3192): Checks if user exists, otherwise logout and show error
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import { type NextRequest,NextResponse } from "next/server"
|
||||
import { AuthError } from "next-auth"
|
||||
|
||||
import { logger } from "@scandic-hotels/common/logger"
|
||||
|
||||
import { env } from "@/env/server"
|
||||
import { internalServerError } from "@/server/errors/next"
|
||||
import { getPublicURL } from "@/server/utils"
|
||||
|
||||
import { signOut } from "@/auth"
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const publicURL = getPublicURL(request)
|
||||
const redirectToSearchParamValue =
|
||||
request.nextUrl.searchParams.get("redirectTo")
|
||||
const redirectToFallback = "/"
|
||||
|
||||
let redirectTo: string = redirectToSearchParamValue || redirectToFallback
|
||||
|
||||
// Make relative URL to absolute URL
|
||||
if (redirectTo.startsWith("/")) {
|
||||
redirectTo = new URL(redirectTo, publicURL).href
|
||||
}
|
||||
|
||||
try {
|
||||
redirectTo = `${env.CURITY_ISSUER_USER}/authn/authenticate/logout?redirect_uri=${encodeURIComponent(redirectTo)}`
|
||||
logger.debug(`[logoutSafely] final redirectUrl: ${redirectTo}`)
|
||||
|
||||
const redirectUrlObj = await signOut({
|
||||
redirectTo,
|
||||
redirect: false,
|
||||
})
|
||||
|
||||
return NextResponse.redirect(redirectUrlObj.redirect)
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
logger.error("signOutSafelyAuthError", { signOutAuthError: error })
|
||||
} else {
|
||||
logger.error("signOutSafelyError", { signOutError: error })
|
||||
}
|
||||
}
|
||||
|
||||
return internalServerError()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { UserNotFound } from "@/components/UserNotFound/UserNotFound"
|
||||
|
||||
import type { Metadata } from "next"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
robots: {
|
||||
index: false,
|
||||
follow: false,
|
||||
},
|
||||
}
|
||||
|
||||
export default function UserNotFoundPage() {
|
||||
return <UserNotFound />
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import SitewideAlert from "@/components/SitewideAlert"
|
||||
import { ToastHandler } from "@/components/TempDesignSystem/Toasts"
|
||||
import AdobeSDKScript from "@/components/TrackingSDK/AdobeSDKScript"
|
||||
import GTMScript from "@/components/TrackingSDK/GTMScript"
|
||||
import { UserExists } from "@/components/UserExists"
|
||||
import { FontPreload } from "@/fonts/font-preloading"
|
||||
import { getMessages } from "@/i18n"
|
||||
import ClientIntlProvider from "@/i18n/Provider"
|
||||
@@ -87,6 +88,7 @@ export default async function RootLayout(
|
||||
<SessionRefresher />
|
||||
<StorageCleaner />
|
||||
<CookieBotConsent />
|
||||
<UserExists />
|
||||
<ReactQueryDevtools initialIsOpen={false} />
|
||||
</BookingFlowTrackingProvider>
|
||||
</RACRouterProvider>
|
||||
|
||||
43
apps/scandic-web/components/UserExists.tsx
Normal file
43
apps/scandic-web/components/UserExists.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
"use client"
|
||||
|
||||
import { redirect } from "next/navigation"
|
||||
import { useSession } from "next-auth/react"
|
||||
|
||||
import { trpc } from "@scandic-hotels/trpc/client"
|
||||
|
||||
import { userNotFound } from "@/constants/routes/errorPages"
|
||||
import { logoutSafely } from "@/constants/routes/handleAuth"
|
||||
|
||||
import useLang from "@/hooks/useLang"
|
||||
import { isValidClientSession } from "@/utils/clientSession"
|
||||
|
||||
export function UserExists() {
|
||||
const { data: session } = useSession()
|
||||
const isUserLoggedIn = isValidClientSession(session)
|
||||
const lang = useLang()
|
||||
|
||||
const { data, isLoading: isLoadingUser } = trpc.user.get.useQuery(undefined, {
|
||||
enabled: isUserLoggedIn,
|
||||
})
|
||||
|
||||
if (!isUserLoggedIn) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (isLoadingUser) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (data && "error" in data && data.error) {
|
||||
switch (data.cause) {
|
||||
case "notfound":
|
||||
redirect(
|
||||
`${logoutSafely[lang]}?redirectTo=${encodeURIComponent(userNotFound[lang])}`
|
||||
)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
.container {
|
||||
margin-top: 0;
|
||||
background: var(--Main-Grey-White);
|
||||
position: relative;
|
||||
border-top: 50px solid var(--Main-Grey-White);
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
box-sizing: content-box;
|
||||
max-width: var(--max-width-page);
|
||||
margin: 0 auto;
|
||||
padding: 70px 30px;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-family:
|
||||
brandon text,
|
||||
Arial,
|
||||
Helvetica,
|
||||
sans-serif;
|
||||
font-size: 32px;
|
||||
line-height: 1;
|
||||
margin: 0;
|
||||
text-transform: uppercase;
|
||||
font-weight: 400;
|
||||
color: #483729;
|
||||
}
|
||||
|
||||
.pitch {
|
||||
margin-top: 32px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-family:
|
||||
Helvetica Neue,
|
||||
Roboto,
|
||||
Helvetica,
|
||||
Arial,
|
||||
sans-serif;
|
||||
font-weight: 300;
|
||||
line-height: normal;
|
||||
text-transform: none;
|
||||
font-size: 20px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 740px) {
|
||||
.content {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 950px) {
|
||||
.header {
|
||||
font-size: 46px;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
28
apps/scandic-web/components/UserNotFound/UserNotFound.tsx
Normal file
28
apps/scandic-web/components/UserNotFound/UserNotFound.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
"use client"
|
||||
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import styles from "./UserNotFound.module.css"
|
||||
|
||||
export function UserNotFound() {
|
||||
const intl = useIntl()
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<h1 className={styles.header}>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "User not found",
|
||||
})}
|
||||
</h1>
|
||||
<div className={styles.pitch}>
|
||||
<p className={styles.text}>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Please try again or contact customer service!",
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
10
apps/scandic-web/constants/routes/errorPages.ts
Normal file
10
apps/scandic-web/constants/routes/errorPages.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { LangRoute } from "@scandic-hotels/common/constants/routes/langRoute"
|
||||
|
||||
export const userNotFound: LangRoute = {
|
||||
en: "/en/error/user-not-found",
|
||||
sv: "/sv/error/user-not-found",
|
||||
no: "/no/error/user-not-found",
|
||||
fi: "/fi/error/user-not-found",
|
||||
da: "/da/error/user-not-found",
|
||||
de: "/de/error/user-not-found",
|
||||
}
|
||||
@@ -32,6 +32,15 @@ export const logout = {
|
||||
sv: "/sv/logga-ut",
|
||||
}
|
||||
|
||||
export const logoutSafely = {
|
||||
da: "/da/logoutSafely",
|
||||
de: "/de/logoutSafely",
|
||||
en: "/en/logoutSafely",
|
||||
fi: "/fi/logoutSafely",
|
||||
no: "/no/logoutSafely",
|
||||
sv: "/sv/logoutSafely",
|
||||
}
|
||||
|
||||
/** @type {import('@scandic-hotels/common/constants/routes/langRoute').LangRoute} */
|
||||
export const logoutUnLocalized = {
|
||||
da: "/da/logout",
|
||||
@@ -58,4 +67,5 @@ export const handleAuth = [
|
||||
...Object.values(verifymagiclink),
|
||||
...Object.values(loginUnLocalized),
|
||||
...Object.values(logoutUnLocalized),
|
||||
...Object.values(logoutSafely),
|
||||
]
|
||||
|
||||
@@ -12,6 +12,7 @@ import * as currentWebLogin from "@/middlewares/currentWebLogin"
|
||||
import * as currentWebLoginEmail from "@/middlewares/currentWebLoginEmail"
|
||||
import * as currentWebLogout from "@/middlewares/currentWebLogout"
|
||||
import * as dateQueryParams from "@/middlewares/dateQueryParams"
|
||||
import * as errorPages from "@/middlewares/errorPages"
|
||||
import * as familyAndFriends from "@/middlewares/familyAndFriends"
|
||||
import * as handleAuth from "@/middlewares/handleAuth"
|
||||
import * as handleDTMC from "@/middlewares/handleDTMC"
|
||||
@@ -67,6 +68,7 @@ export const middleware: NextMiddleware = async (request, event) => {
|
||||
dateQueryParams,
|
||||
legacySearchParams,
|
||||
bookingFlow,
|
||||
errorPages,
|
||||
familyAndFriends,
|
||||
sasXScandic,
|
||||
cmsContent,
|
||||
|
||||
20
apps/scandic-web/middlewares/errorPages.ts
Normal file
20
apps/scandic-web/middlewares/errorPages.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { type NextMiddleware, NextResponse } from "next/server"
|
||||
|
||||
import { getDefaultRequestHeaders } from "./utils"
|
||||
|
||||
import type { MiddlewareMatcher } from "@/types/middleware"
|
||||
|
||||
export const middleware: NextMiddleware = async (request) => {
|
||||
const headers = getDefaultRequestHeaders(request)
|
||||
headers.set("X-Robots-Tag", "noindex, nofollow")
|
||||
|
||||
return NextResponse.next({
|
||||
request: {
|
||||
headers,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const matcher: MiddlewareMatcher = (request) => {
|
||||
return !!request.nextUrl.pathname.match(/^\/(da|de|en|fi|no|sv)\/(error)/)
|
||||
}
|
||||
Reference in New Issue
Block a user