diff --git a/components/Current/Header/TopMenu/index.tsx b/components/Current/Header/TopMenu/index.tsx
index 69d23798e..be0e99d97 100644
--- a/components/Current/Header/TopMenu/index.tsx
+++ b/components/Current/Header/TopMenu/index.tsx
@@ -1,7 +1,6 @@
import { logout } from "@/constants/routes/handleAuth"
import { serverClient } from "@/lib/trpc/server"
-import { auth } from "@/auth"
import Link from "@/components/TempDesignSystem/Link"
import { getIntl } from "@/i18n"
@@ -23,9 +22,7 @@ export default async function TopMenu({
lang,
}: TopMenuProps) {
const { formatMessage } = await getIntl()
- const session = await auth()
- const user = session ? await serverClient().user.get() : null
-
+ const user = await serverClient().user.name()
return (
@@ -46,7 +43,7 @@ export default async function TopMenu({
))}
- {session ? (
+ {user ? (
<>
{user ? (
case LoyaltyComponentEnum.overview_table:
- return
+ return
default:
return null
}
diff --git a/server/context.ts b/server/context.ts
index 537719540..2c4c235ee 100644
--- a/server/context.ts
+++ b/server/context.ts
@@ -10,7 +10,7 @@ import { unauthorizedError } from "./errors/trpc"
typeof auth
type CreateContextOptions = {
- auth: () => Promise
+ auth: () => Promise
lang: Lang
pathname: string
uid?: string | null
@@ -50,7 +50,7 @@ export function createContext() {
const session = await auth()
const webToken = webviewTokenCookie?.value
if (!session?.token && !webToken) {
- throw unauthorizedError()
+ return null
}
return session || ({ token: { access_token: webToken } } as Session)
diff --git a/server/routers/user/query.ts b/server/routers/user/query.ts
index c80a086c5..30a77d9c4 100644
--- a/server/routers/user/query.ts
+++ b/server/routers/user/query.ts
@@ -1,9 +1,13 @@
import * as api from "@/lib/api"
-import { protectedProcedure, router } from "@/server/trpc"
+import {
+ protectedProcedure,
+ router,
+ safeProtectedProcedure,
+} from "@/server/trpc"
import { countries } from "@/components/TempDesignSystem/Form/Country/countries"
import * as maskValue from "@/utils/maskValue"
-import { getMembershipCards } from "@/utils/user"
+import { getMembership, getMembershipCards } from "@/utils/user"
import {
friendTransactionsInput,
@@ -19,6 +23,37 @@ import {
} from "./output"
import { benefits, extendedUser, nextLevelPerks } from "./temp"
+import type { Session } from "next-auth"
+
+async function getVerifiedUser({ session }: { session: Session }) {
+ const apiResponse = await api.get(api.endpoints.v1.profile, {
+ cache: "no-store",
+ headers: {
+ Authorization: `Bearer ${session.token.access_token}`,
+ },
+ })
+
+ if (!apiResponse.ok) {
+ return null
+ }
+
+ const apiJson = await apiResponse.json()
+ if (!apiJson.data?.attributes) {
+ console.error(`User has no data - (user: ${JSON.stringify(session.user)})`)
+ return null
+ }
+
+ const verifiedData = getUserSchema.safeParse(apiJson.data.attributes)
+ if (!verifiedData.success) {
+ console.info(
+ `Failed to validate User - (User: ${JSON.stringify(session.user)})`
+ )
+ console.error(verifiedData.error)
+ return null
+ }
+ return verifiedData
+}
+
function fakingRequest(payload: T): Promise {
return new Promise((resolve) => {
setTimeout(() => {
@@ -31,45 +66,9 @@ export const userQueryRouter = router({
get: protectedProcedure
.input(getUserInputSchema)
.query(async function getUser({ ctx, input }) {
- const apiResponse = await api.get(api.endpoints.v1.profile, {
- cache: "no-store",
- headers: {
- Authorization: `Bearer ${ctx.session.token.access_token}`,
- },
- })
+ const verifiedData = await getVerifiedUser({ session: ctx.session })
- if (!apiResponse.ok) {
- // switch (apiResponse.status) {
- // case 400:
- // throw badRequestError()
- // case 401:
- // throw unauthorizedError()
- // case 403:
- // throw forbiddenError()
- // default:
- // throw internalServerError()
- // }
- console.info(`API Response Failed - Getting User`)
- console.info(`User: (${JSON.stringify(ctx.session.user)})`)
- console.error(apiResponse)
- return null
- }
-
- const apiJson = await apiResponse.json()
- if (!apiJson.data?.attributes) {
- // throw notFound(apiJson)
- console.error(
- `User has no data - (user: ${JSON.stringify(ctx.session.user)})`
- )
- return null
- }
-
- const verifiedData = getUserSchema.safeParse(apiJson.data.attributes)
- if (!verifiedData.success) {
- console.info(
- `Failed to validate User - (User: ${JSON.stringify(ctx.session.user)})`
- )
- console.error(verifiedData.error)
+ if (!verifiedData) {
return null
}
@@ -119,7 +118,33 @@ export const userQueryRouter = router({
return user
}),
+ name: safeProtectedProcedure.query(async function ({ ctx }) {
+ if (!ctx.session) {
+ return null
+ }
+ const verifiedData = await getVerifiedUser({ session: ctx.session })
+ if (!verifiedData) {
+ return null
+ }
+ return {
+ firstName: verifiedData.data.firstName,
+ lastName: verifiedData.data.lastName,
+ }
+ }),
+ membershipLevel: safeProtectedProcedure.query(async function ({ ctx }) {
+ if (!ctx.session) {
+ return null
+ }
+ const verifiedData = await getVerifiedUser({ session: ctx.session })
+
+ if (!verifiedData) {
+ return null
+ }
+
+ const membershipLevel = getMembership(verifiedData.data.memberships)
+ return membershipLevel
+ }),
benefits: router({
current: protectedProcedure.query(async function (opts) {
// TODO: Make request to get user data from Scandic API
diff --git a/server/trpc.ts b/server/trpc.ts
index 3f7cd3c70..1caf32b53 100644
--- a/server/trpc.ts
+++ b/server/trpc.ts
@@ -2,10 +2,16 @@ import { initTRPC } from "@trpc/server"
import { env } from "@/env/server"
-import { badRequestError, sessionExpiredError } from "./errors/trpc"
+import {
+ badRequestError,
+ sessionExpiredError,
+ unauthorizedError,
+} from "./errors/trpc"
import { transformer } from "./transformer"
import { langInput } from "./utils"
+import type { Session } from "next-auth"
+
import type { Meta } from "@/types/trpc/meta"
import type { Context } from "./context"
@@ -57,6 +63,10 @@ export const protectedProcedure = t.procedure.use(async function (opts) {
console.info(`path: ${opts.path} | type: ${opts.type}`)
}
+ if (!session) {
+ throw unauthorizedError()
+ }
+
if (session?.error === "RefreshAccessTokenError") {
throw sessionExpiredError()
}
@@ -67,3 +77,25 @@ export const protectedProcedure = t.procedure.use(async function (opts) {
},
})
})
+
+export const safeProtectedProcedure = t.procedure.use(async function (opts) {
+ const authRequired = opts.meta?.authRequired ?? true
+
+ let session: Session | null = await opts.ctx.auth()
+ if (!authRequired && env.NODE_ENV === "development") {
+ console.info(
+ `❌❌❌❌ You are opting out of authorization, if its done on purpose maybe you should use the publicProcedure instead. ❌❌❌❌`
+ )
+ console.info(`path: ${opts.path} | type: ${opts.type}`)
+ }
+
+ if (!session || session.error === "RefreshAccessTokenError") {
+ session = null
+ }
+
+ return opts.next({
+ ctx: {
+ session,
+ },
+ })
+})
diff --git a/types/components/current/header/mainMenu.ts b/types/components/current/header/mainMenu.ts
index 4251fd529..8e468e8cc 100644
--- a/types/components/current/header/mainMenu.ts
+++ b/types/components/current/header/mainMenu.ts
@@ -16,6 +16,6 @@ export type MainMenuProps = {
languageSwitcher: React.ReactNode | null
myPagesMobileDropdown: React.ReactNode | null
bookingHref: string
- user: User | null
+ user: Pick | null
lang: Lang
}
diff --git a/types/components/loyalty/blocks.ts b/types/components/loyalty/blocks.ts
index f9f337344..c8db57354 100644
--- a/types/components/loyalty/blocks.ts
+++ b/types/components/loyalty/blocks.ts
@@ -7,9 +7,9 @@ import {
RteBlockContent,
} from "@/server/routers/contentstack/loyaltyPage/output"
-import type { IntlFormatters } from "@formatjs/intl"
+import { MembershipLevel } from "@/utils/user"
-import { User } from "@/types/user"
+import type { IntlFormatters } from "@formatjs/intl"
export type BlocksProps = {
blocks: Block[]
@@ -32,7 +32,7 @@ export type Content = { content: RteBlockContent["content"]["content"] }
type Benefit = { title: string }
-export type OverviewTableProps = { user: User | null }
+export type OverviewTableProps = { activeMembership: MembershipLevel | null }
export type Level = {
level: membershipLevels
diff --git a/utils/user.ts b/utils/user.ts
index 052826eaf..57f4e3e16 100644
--- a/utils/user.ts
+++ b/utils/user.ts
@@ -15,6 +15,7 @@ export function getMembership(memberships: User["memberships"]) {
membership.membershipType.toLowerCase() === scandicMemberships.guestpr
)
}
+export type MembershipLevel = ReturnType
export function getMembershipCards(
memberships: z.infer