Merged in feat/3614-basicInfo (pull request #3427)
feat(SW-3614): use new loyalty prop in basicProfile * feat(SW-3614): use new loyalty prop in basicProfile * PR fixes Approved-by: Matilda Landström
This commit is contained in:
@@ -1,8 +1,12 @@
|
|||||||
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
|
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
|
||||||
import { getEurobonusMembership } from "@scandic-hotels/trpc/routers/user/helpers"
|
import {
|
||||||
|
getEurobonusMembership,
|
||||||
|
scandicMembershipTypes,
|
||||||
|
} from "@scandic-hotels/trpc/routers/user/helpers"
|
||||||
|
|
||||||
import { env } from "@/env/server"
|
import { env } from "@/env/server"
|
||||||
import {
|
import {
|
||||||
|
getBasicProfileSafely,
|
||||||
getProfileSafely,
|
getProfileSafely,
|
||||||
getProfilingConsent,
|
getProfilingConsent,
|
||||||
} from "@/lib/trpc/memoizedRequests"
|
} from "@/lib/trpc/memoizedRequests"
|
||||||
@@ -85,10 +89,10 @@ async function MyPagesLayoutBase({
|
|||||||
breadcrumbs,
|
breadcrumbs,
|
||||||
children,
|
children,
|
||||||
}: MyPagesLayoutProps) {
|
}: MyPagesLayoutProps) {
|
||||||
const profile = await getProfileSafely()
|
const profile = await getBasicProfileSafely()
|
||||||
const eurobonusMembership = profile?.loyalty
|
const eurobonusMembership = profile?.loyalty?.memberships?.find(
|
||||||
? getEurobonusMembership(profile.loyalty)
|
(m) => m.membershipType === scandicMembershipTypes.SAS_EB
|
||||||
: null
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { redirect } from "next/navigation"
|
import { redirect } from "next/navigation"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
import { getEurobonusMembership } from "@scandic-hotels/trpc/routers/user/helpers"
|
import { scandicMembershipTypes } from "@scandic-hotels/trpc/routers/user/helpers"
|
||||||
|
|
||||||
import { getProfileSafely } from "@/lib/trpc/memoizedRequests"
|
import { getBasicProfileSafely } from "@/lib/trpc/memoizedRequests"
|
||||||
|
|
||||||
import { SASModal } from "../components/SASModal"
|
import { SASModal } from "../components/SASModal"
|
||||||
import { LinkAccountForm } from "./LinkAccountForm"
|
import { LinkAccountForm } from "./LinkAccountForm"
|
||||||
@@ -12,11 +12,13 @@ export default async function SASxScandicLinkPage(
|
|||||||
props: PageProps<"/[lang]/sas-x-scandic/link">
|
props: PageProps<"/[lang]/sas-x-scandic/link">
|
||||||
) {
|
) {
|
||||||
const params = await props.params
|
const params = await props.params
|
||||||
const profile = await getProfileSafely()
|
const profile = await getBasicProfileSafely()
|
||||||
|
|
||||||
if (!profile || !profile.loyalty) return null
|
if (!profile || !profile.loyalty) return null
|
||||||
|
|
||||||
const eurobonusMembership = getEurobonusMembership(profile.loyalty)
|
const eurobonusMembership = profile.loyalty.memberships?.some(
|
||||||
|
(m) => m.membershipType === scandicMembershipTypes.SAS_EB
|
||||||
|
)
|
||||||
|
|
||||||
if (eurobonusMembership) {
|
if (eurobonusMembership) {
|
||||||
redirect(`/${params.lang}/sas-x-scandic/error?errorCode=alreadyLinked`)
|
redirect(`/${params.lang}/sas-x-scandic/error?errorCode=alreadyLinked`)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import ButtonLink from "@scandic-hotels/design-system/ButtonLink"
|
import ButtonLink from "@scandic-hotels/design-system/ButtonLink"
|
||||||
import Image from "@scandic-hotels/design-system/Image"
|
import Image from "@scandic-hotels/design-system/Image"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
import { getEurobonusMembership } from "@scandic-hotels/trpc/routers/user/helpers"
|
import { scandicMembershipTypes } from "@scandic-hotels/trpc/routers/user/helpers"
|
||||||
|
|
||||||
import { getProfile } from "@/lib/trpc/memoizedRequests"
|
import { getBasicProfileSafely } from "@/lib/trpc/memoizedRequests"
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
import { getIntl } from "@/i18n"
|
||||||
import desktopBackground from "@/public/_static/img/sas/sas-scandic-link-account-banner-desktop.png"
|
import desktopBackground from "@/public/_static/img/sas/sas-scandic-link-account-banner-desktop.png"
|
||||||
@@ -17,12 +17,14 @@ export default async function SASLinkAccountBanner(
|
|||||||
props: DynamicContentProps["dynamic_content"]
|
props: DynamicContentProps["dynamic_content"]
|
||||||
) {
|
) {
|
||||||
const intl = await getIntl()
|
const intl = await getIntl()
|
||||||
const user = await getProfile()
|
const user = await getBasicProfileSafely()
|
||||||
|
|
||||||
if (!user || "error" in user || !user.loyalty) {
|
if (!user || "error" in user || !user.loyalty) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const sasMembership = getEurobonusMembership(user.loyalty)
|
const sasMembership = user.loyalty.memberships?.some(
|
||||||
|
(m) => m.membershipType === scandicMembershipTypes.SAS_EB
|
||||||
|
)
|
||||||
if (sasMembership) {
|
if (sasMembership) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,17 @@ export const getBasicProfile = cache(async function getMemoizedBasicProfile() {
|
|||||||
return caller.user.getBasic()
|
return caller.user.getBasic()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const getBasicProfileSafely = cache(
|
||||||
|
async function getMemoizedBasicProfile() {
|
||||||
|
try {
|
||||||
|
const caller = await serverClient()
|
||||||
|
return caller.user.getBasic()
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
export const getProfileSafely = cache(
|
export const getProfileSafely = cache(
|
||||||
async function getMemoizedProfileSafely() {
|
async function getMemoizedProfileSafely() {
|
||||||
const caller = await serverClient()
|
const caller = await serverClient()
|
||||||
@@ -59,13 +70,6 @@ export const getMembershipLevelSafely = cache(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const getMembershipCards = cache(
|
|
||||||
async function getMemoizedMembershipCards() {
|
|
||||||
const caller = await serverClient()
|
|
||||||
return caller.user.membershipCards()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
export const getHotelsByCSFilter = cache(async function getMemoizedHotels(
|
export const getHotelsByCSFilter = cache(async function getMemoizedHotels(
|
||||||
input: GetHotelsByCSFilterInput
|
input: GetHotelsByCSFilterInput
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -3,22 +3,25 @@ import { cache } from "react"
|
|||||||
import * as routes from "@scandic-hotels/common/constants/routes/myPages"
|
import * as routes from "@scandic-hotels/common/constants/routes/myPages"
|
||||||
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
||||||
|
|
||||||
import { getEurobonusMembership } from "../../user/helpers"
|
import { scandicMembershipTypes } from "../../user/helpers"
|
||||||
|
|
||||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
|
|
||||||
import type { UserLoyalty } from "../../../types/user"
|
import type { BasicUserProfile } from "../../../types/user"
|
||||||
import type { MyPagesLink } from "./MyPagesLink"
|
import type { MyPagesLink } from "./MyPagesLink"
|
||||||
|
|
||||||
export const getPrimaryLinks = cache(
|
export const getPrimaryLinks = cache(
|
||||||
async ({
|
async ({
|
||||||
lang,
|
lang,
|
||||||
userLoyalty,
|
basicUserLoyalty,
|
||||||
}: {
|
}: {
|
||||||
lang: Lang
|
lang: Lang
|
||||||
userLoyalty?: UserLoyalty
|
basicUserLoyalty?: BasicUserProfile["loyalty"]
|
||||||
}): Promise<MyPagesLink[]> => {
|
}): Promise<MyPagesLink[]> => {
|
||||||
const showSASLink = userLoyalty ? isScandicXSASActive(userLoyalty) : false
|
const showSASLink = basicUserLoyalty?.memberships?.some(
|
||||||
|
(m) => m.membershipType === scandicMembershipTypes.SAS_EB
|
||||||
|
)
|
||||||
|
|
||||||
const [showTeamMemberLink] = await safeTry(showTeamMemberCard())
|
const [showTeamMemberLink] = await safeTry(showTeamMemberCard())
|
||||||
|
|
||||||
const menuItems: MyPagesLink[] = [
|
const menuItems: MyPagesLink[] = [
|
||||||
@@ -64,11 +67,6 @@ export const getPrimaryLinks = cache(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const isScandicXSASActive = (loyalty: UserLoyalty) => {
|
|
||||||
const eurobonusMembership = getEurobonusMembership(loyalty)
|
|
||||||
return Boolean(eurobonusMembership)
|
|
||||||
}
|
|
||||||
|
|
||||||
const showTeamMemberCard = cache(async () => {
|
const showTeamMemberCard = cache(async () => {
|
||||||
async function getIsTeamMember() {
|
async function getIsTeamMember() {
|
||||||
// TODO: Implement this check
|
// TODO: Implement this check
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
|||||||
|
|
||||||
import { safeProtectedProcedure } from "../../../procedures"
|
import { safeProtectedProcedure } from "../../../procedures"
|
||||||
import { isValidSession } from "../../../utils/session"
|
import { isValidSession } from "../../../utils/session"
|
||||||
import { getVerifiedUser } from "../../user/utils/getVerifiedUser"
|
import { getBasicUser } from "../../user/utils/getBasicUser"
|
||||||
import { getPrimaryLinks } from "./getPrimaryLinks"
|
import { getPrimaryLinks } from "./getPrimaryLinks"
|
||||||
import { getSecondaryLinks } from "./getSecondaryLinks"
|
import { getSecondaryLinks } from "./getSecondaryLinks"
|
||||||
|
|
||||||
@@ -40,14 +40,14 @@ export const myPagesNavigation = safeProtectedProcedure
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [user, error] = await safeTry(
|
const [user, error] = await safeTry(
|
||||||
getVerifiedUser({ token: ctx.session.token })
|
getBasicUser({ token: ctx.session.token })
|
||||||
)
|
)
|
||||||
if (!user || error) {
|
if (!user || error) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const [primaryLinks, secondaryLinks] = await Promise.all([
|
const [primaryLinks, secondaryLinks] = await Promise.all([
|
||||||
getPrimaryLinks({ lang, userLoyalty: user.loyalty }),
|
getPrimaryLinks({ lang, basicUserLoyalty: user.loyalty }),
|
||||||
getSecondaryLinks({ lang }),
|
getSecondaryLinks({ lang }),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ export const performLevelUpgrade = protectedProcedure
|
|||||||
const [profile, error] = await safeTry(
|
const [profile, error] = await safeTry(
|
||||||
getBasicUser({ token: ctx.session.token })
|
getBasicUser({ token: ctx.session.token })
|
||||||
)
|
)
|
||||||
if (!profile || error) {
|
if (!profile || error || !profile.loyalty?.tier) {
|
||||||
return { tierMatchState: "error" }
|
return { tierMatchState: "error" }
|
||||||
}
|
}
|
||||||
const currentLevel = profile.tier
|
const currentLevel = profile.loyalty.tier
|
||||||
|
|
||||||
sasLogger.debug("tier match started")
|
sasLogger.debug("tier match started")
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type {
|
|||||||
export enum scandicMembershipTypes {
|
export enum scandicMembershipTypes {
|
||||||
SCANDIC_NATIVE = "SCANDIC_NATIVE",
|
SCANDIC_NATIVE = "SCANDIC_NATIVE",
|
||||||
SAS_EB = "SAS_EB",
|
SAS_EB = "SAS_EB",
|
||||||
|
"OTHER" = "OTHER",
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isScandicNativeMembership(
|
export function isScandicNativeMembership(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { z } from "zod"
|
|||||||
|
|
||||||
import { countriesMap } from "../../constants/countries"
|
import { countriesMap } from "../../constants/countries"
|
||||||
import { imageSchema } from "../../routers/hotels/schemas/image"
|
import { imageSchema } from "../../routers/hotels/schemas/image"
|
||||||
import { getFriendsMembership } from "./helpers"
|
import { getFriendsMembership, scandicMembershipTypes } from "./helpers"
|
||||||
|
|
||||||
const scandicFriendsTier = z.enum(["L1", "L2", "L3", "L4", "L5", "L6", "L7"])
|
const scandicFriendsTier = z.enum(["L1", "L2", "L3", "L4", "L5", "L6", "L7"])
|
||||||
const sasEurobonusTier = z.enum(["EBB", "EBS", "EBG", "EBD", "EBP"])
|
const sasEurobonusTier = z.enum(["EBB", "EBS", "EBG", "EBD", "EBP"])
|
||||||
@@ -23,7 +23,7 @@ const otherMembershipSchema = z
|
|||||||
|
|
||||||
export const sasMembershipSchema = z
|
export const sasMembershipSchema = z
|
||||||
.object({
|
.object({
|
||||||
type: z.literal("SAS_EB"),
|
type: z.literal(scandicMembershipTypes.SAS_EB),
|
||||||
tier: sasEurobonusTier,
|
tier: sasEurobonusTier,
|
||||||
nextTier: sasEurobonusTier.nullish(),
|
nextTier: sasEurobonusTier.nullish(),
|
||||||
spendablePoints: z.number().nullish(),
|
spendablePoints: z.number().nullish(),
|
||||||
@@ -43,7 +43,7 @@ export const sasMembershipSchema = z
|
|||||||
|
|
||||||
export const friendsMembershipSchema = z
|
export const friendsMembershipSchema = z
|
||||||
.object({
|
.object({
|
||||||
type: z.literal("SCANDIC_NATIVE"),
|
type: z.literal(scandicMembershipTypes.SCANDIC_NATIVE),
|
||||||
tier: scandicFriendsTier,
|
tier: scandicFriendsTier,
|
||||||
nextTier: scandicFriendsTier.nullish(),
|
nextTier: scandicFriendsTier.nullish(),
|
||||||
pointsToNextTier: z.number().nullish(),
|
pointsToNextTier: z.number().nullish(),
|
||||||
@@ -140,8 +140,6 @@ export const getBasicUserSchema = z.object({
|
|||||||
lastName: z.string(),
|
lastName: z.string(),
|
||||||
phoneNumber: z.string().optional(),
|
phoneNumber: z.string().optional(),
|
||||||
profileId: z.string().optional(),
|
profileId: z.string().optional(),
|
||||||
membershipNumber: z.string(),
|
|
||||||
tier: scandicFriendsTier,
|
|
||||||
address: z
|
address: z
|
||||||
.object({
|
.object({
|
||||||
city: z.string().optional(),
|
city: z.string().optional(),
|
||||||
@@ -152,6 +150,21 @@ export const getBasicUserSchema = z.object({
|
|||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
.nullable(),
|
.nullable(),
|
||||||
|
loyalty: z
|
||||||
|
.object({
|
||||||
|
tier: scandicFriendsTier,
|
||||||
|
tierExpires: z.string(),
|
||||||
|
memberships: z.array(
|
||||||
|
z.object({
|
||||||
|
membershipType: z
|
||||||
|
.nativeEnum(scandicMembershipTypes)
|
||||||
|
.catch(scandicMembershipTypes.OTHER),
|
||||||
|
membershipNumber: z.string(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.nullable(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const creditCardSchema = z
|
export const creditCardSchema = z
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
|
|||||||
import { safeProtectedProcedure } from "../../../procedures"
|
import { safeProtectedProcedure } from "../../../procedures"
|
||||||
import { isValidSession } from "../../../utils/session"
|
import { isValidSession } from "../../../utils/session"
|
||||||
import { getEuroBonusProfileData } from "../../partners/sas/getEuroBonusProfile"
|
import { getEuroBonusProfileData } from "../../partners/sas/getEuroBonusProfile"
|
||||||
|
import { scandicMembershipTypes } from "../helpers"
|
||||||
import { getBasicUser } from "../utils/getBasicUser"
|
import { getBasicUser } from "../utils/getBasicUser"
|
||||||
|
|
||||||
import type { LoginType } from "@scandic-hotels/common/constants/loginType"
|
import type { LoginType } from "@scandic-hotels/common/constants/loginType"
|
||||||
@@ -62,8 +63,10 @@ async function getScandicFriendsUserTrackingData(session: Session | null) {
|
|||||||
loginStatus: "logged in",
|
loginStatus: "logged in",
|
||||||
loginType: session.token.loginType as LoginType,
|
loginType: session.token.loginType as LoginType,
|
||||||
memberId: verifiedUserData.profileId,
|
memberId: verifiedUserData.profileId,
|
||||||
membershipNumber: verifiedUserData.membershipNumber,
|
membershipNumber: verifiedUserData.loyalty?.memberships?.find(
|
||||||
memberLevel: verifiedUserData?.tier,
|
(m) => m.membershipType === scandicMembershipTypes.SCANDIC_NATIVE
|
||||||
|
)?.membershipNumber,
|
||||||
|
memberLevel: verifiedUserData.loyalty?.tier,
|
||||||
loginAction: "login success",
|
loginAction: "login success",
|
||||||
memberType,
|
memberType,
|
||||||
}
|
}
|
||||||
@@ -134,7 +137,9 @@ async function getScandicFriendsDataHelper(scandicUserToken: string | null) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
memberId: verifiedUserData.profileId,
|
memberId: verifiedUserData.profileId,
|
||||||
membershipNumber: verifiedUserData.membershipNumber,
|
membershipNumber: verifiedUserData.loyalty?.memberships?.find(
|
||||||
memberLevel: verifiedUserData.tier,
|
(m) => m.membershipType === scandicMembershipTypes.SCANDIC_NATIVE
|
||||||
|
)?.membershipNumber,
|
||||||
|
memberLevel: verifiedUserData.loyalty?.tier,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
serverErrorByStatus,
|
serverErrorByStatus,
|
||||||
sessionExpiredError,
|
sessionExpiredError,
|
||||||
} from "../../../errors"
|
} from "../../../errors"
|
||||||
|
import { scandicMembershipTypes } from "../helpers"
|
||||||
import { getBasicUserSchema } from "../output"
|
import { getBasicUserSchema } from "../output"
|
||||||
|
|
||||||
import type z from "zod"
|
import type z from "zod"
|
||||||
@@ -63,15 +64,19 @@ export const getBasicUser = cache(
|
|||||||
|
|
||||||
function addUserToSentry(apiJson: unknown) {
|
function addUserToSentry(apiJson: unknown) {
|
||||||
const typedData = apiJson as DeepPartial<z.input<typeof getBasicUserSchema>>
|
const typedData = apiJson as DeepPartial<z.input<typeof getBasicUserSchema>>
|
||||||
|
const memberShipNumber = typedData?.loyalty?.memberships?.find(
|
||||||
|
(m) => m?.membershipType === scandicMembershipTypes.SCANDIC_NATIVE
|
||||||
|
)?.membershipNumber
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof typedData?.profileId === "undefined" ||
|
typeof typedData?.profileId === "undefined" ||
|
||||||
typeof typedData?.membershipNumber === "undefined"
|
typeof memberShipNumber === "undefined"
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Sentry.setUser({
|
Sentry.setUser({
|
||||||
id: typedData?.profileId,
|
id: typedData?.profileId,
|
||||||
username: typedData?.membershipNumber,
|
username: memberShipNumber,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type { getFriendsMembership } from "../routers/user/helpers"
|
|||||||
import type {
|
import type {
|
||||||
creditCardSchema,
|
creditCardSchema,
|
||||||
friendsMembershipSchema,
|
friendsMembershipSchema,
|
||||||
|
getBasicUserSchema,
|
||||||
getUserSchema,
|
getUserSchema,
|
||||||
sasMembershipSchema,
|
sasMembershipSchema,
|
||||||
userLoyaltySchema,
|
userLoyaltySchema,
|
||||||
@@ -23,6 +24,8 @@ export type Membership = UserLoyalty["memberships"][number]
|
|||||||
export type NativeFriendsMembership = z.output<typeof friendsMembershipSchema>
|
export type NativeFriendsMembership = z.output<typeof friendsMembershipSchema>
|
||||||
export type EurobonusMembership = z.output<typeof sasMembershipSchema>
|
export type EurobonusMembership = z.output<typeof sasMembershipSchema>
|
||||||
|
|
||||||
|
export type BasicUserProfile = z.output<typeof getBasicUserSchema>
|
||||||
|
|
||||||
export type FriendsMembership = ReturnType<typeof getFriendsMembership>
|
export type FriendsMembership = ReturnType<typeof getFriendsMembership>
|
||||||
|
|
||||||
export type EurobonusTier = EurobonusMembership["tier"]
|
export type EurobonusTier = EurobonusMembership["tier"]
|
||||||
|
|||||||
Reference in New Issue
Block a user