Merged in feat/sw-1732-trigger-tier-match (pull request #1408)
SW-1732 Trigger SAS tier match * Add endpoint for SAS tier match * Add comment about future fix * Move tier match to background request on my-pages/* * Log result from tier match * Clean up name etc * Fix tier matched toast Approved-by: Joakim Jäderberg
This commit is contained in:
@@ -117,7 +117,14 @@ export async function GET(
|
|||||||
/** Record<string, any> is next-auth typings */
|
/** Record<string, any> is next-auth typings */
|
||||||
const params: Record<string, any> = {
|
const params: Record<string, any> = {
|
||||||
ui_locales: context.params.lang,
|
ui_locales: context.params.lang,
|
||||||
scope: ["openid", "profile", "booking", "profile_link", "availability"],
|
scope: [
|
||||||
|
"openid",
|
||||||
|
"profile",
|
||||||
|
"booking",
|
||||||
|
"profile_link",
|
||||||
|
"profile_matchtier",
|
||||||
|
"availability",
|
||||||
|
],
|
||||||
/**
|
/**
|
||||||
* The `acr_values` param is used to make Curity display the proper login
|
* The `acr_values` param is used to make Curity display the proper login
|
||||||
* page for Scandic. Without the parameter Curity presents some choices
|
* page for Scandic. Without the parameter Curity presents some choices
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import { trpc } from "@/lib/trpc/client"
|
|
||||||
|
|
||||||
import Refresh from "@/components/Icons/Refresh"
|
|
||||||
import { Loading } from "@/components/Loading"
|
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
|
||||||
import { toast } from "@/components/TempDesignSystem/Toasts"
|
|
||||||
|
|
||||||
import styles from "./levelupgradebutton.module.css"
|
|
||||||
|
|
||||||
export function LevelUpgradeButton() {
|
|
||||||
const intl = useIntl()
|
|
||||||
|
|
||||||
const { mutate, isPending } =
|
|
||||||
trpc.partner.sas.performLevelUpgrade.useMutation({
|
|
||||||
onSuccess() {
|
|
||||||
toast.success(intl.formatMessage({ id: "Level upgraded" }))
|
|
||||||
},
|
|
||||||
onError() {
|
|
||||||
toast.error(intl.formatMessage({ id: "Failed to upgrade level" }))
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleClick = () => {
|
|
||||||
mutate()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
intent="primary"
|
|
||||||
theme="primaryLight"
|
|
||||||
onClick={handleClick}
|
|
||||||
className={styles.button}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={styles.textContainer}
|
|
||||||
style={{ visibility: isPending ? "hidden" : "visible" }}
|
|
||||||
>
|
|
||||||
<Refresh color="currentColor" />
|
|
||||||
{intl.formatMessage({ id: "Check for level upgrade" })}
|
|
||||||
</div>
|
|
||||||
{isPending && <Loading color="white" className={styles.loading} />}
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
.button {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
& .textContainer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--Spacing-x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
|
||||||
width: fit-content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
position: absolute;
|
|
||||||
&.hidden {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
62
apps/scandic-web/components/MyPages/SASLevelUpgradeCheck.tsx
Normal file
62
apps/scandic-web/components/MyPages/SASLevelUpgradeCheck.tsx
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useRef } from "react"
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { TIER_TO_FRIEND_MAP } from "@/constants/membershipLevels"
|
||||||
|
import { trpc } from "@/lib/trpc/client"
|
||||||
|
|
||||||
|
import { toast } from "@/components/TempDesignSystem/Toasts"
|
||||||
|
|
||||||
|
export function SASLevelUpgradeCheck() {
|
||||||
|
const firedRef = useRef(false)
|
||||||
|
const intl = useIntl()
|
||||||
|
|
||||||
|
const { mutate } = trpc.partner.sas.performLevelUpgrade.useMutation({
|
||||||
|
onSuccess(result) {
|
||||||
|
switch (result.tierMatchState) {
|
||||||
|
case "matched":
|
||||||
|
toast.success(
|
||||||
|
intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: "Your SAS level has upgraded you to {level}!",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
level: TIER_TO_FRIEND_MAP[result.toLevel],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
break
|
||||||
|
// TODO remove the logs, but keep for now to ease testing
|
||||||
|
case "notLinked":
|
||||||
|
console.log("[sas] not linked - this should never happen")
|
||||||
|
break
|
||||||
|
case "error":
|
||||||
|
console.log("[sas] something went wrong")
|
||||||
|
break
|
||||||
|
case "cached":
|
||||||
|
console.log("[sas] cached")
|
||||||
|
break
|
||||||
|
case "alreadyMatched":
|
||||||
|
console.log("[sas] already matched")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError() {
|
||||||
|
console.log("[sas] something went wrong")
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// We must make sure this only runs once to avoid sending multiple notifications to the user.
|
||||||
|
// This aint great, but this entire thing is temporary until tier matching is event based on the server.
|
||||||
|
if (firedRef.current) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mutate()
|
||||||
|
firedRef.current = true
|
||||||
|
}, [mutate])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
@@ -1,16 +1,23 @@
|
|||||||
import { logout } from "@/constants/routes/handleAuth"
|
import { logout } from "@/constants/routes/handleAuth"
|
||||||
|
import { getProfileSafely } from "@/lib/trpc/memoizedRequests"
|
||||||
import { serverClient } from "@/lib/trpc/server"
|
import { serverClient } from "@/lib/trpc/server"
|
||||||
|
|
||||||
|
import { SASLevelUpgradeCheck } from "@/components/MyPages/SASLevelUpgradeCheck"
|
||||||
import Divider from "@/components/TempDesignSystem/Divider"
|
import Divider from "@/components/TempDesignSystem/Divider"
|
||||||
import Link from "@/components/TempDesignSystem/Link"
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||||
import { getIntl } from "@/i18n"
|
import { getIntl } from "@/i18n"
|
||||||
import { getLang } from "@/i18n/serverContext"
|
import { getLang } from "@/i18n/serverContext"
|
||||||
|
import { getEurobonusMembership } from "@/utils/user"
|
||||||
|
|
||||||
import styles from "./sidebar.module.css"
|
import styles from "./sidebar.module.css"
|
||||||
|
|
||||||
export default async function SidebarMyPages() {
|
export default async function SidebarMyPages() {
|
||||||
const intl = await getIntl()
|
const intl = await getIntl()
|
||||||
|
const profile = await getProfileSafely()
|
||||||
|
const eurobonusMembership = profile
|
||||||
|
? getEurobonusMembership(profile.memberships)
|
||||||
|
: null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={styles.sidebar}>
|
<aside className={styles.sidebar}>
|
||||||
@@ -22,6 +29,7 @@ export default async function SidebarMyPages() {
|
|||||||
<PrimaryLinks />
|
<PrimaryLinks />
|
||||||
<SecondaryLinks />
|
<SecondaryLinks />
|
||||||
</nav>
|
</nav>
|
||||||
|
{eurobonusMembership && <SASLevelUpgradeCheck />}
|
||||||
</aside>
|
</aside>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -777,6 +777,7 @@
|
|||||||
"You must accept the terms and conditions": "You must accept the terms and conditions",
|
"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'",
|
"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 Challenges Conquer & Earn!": "Dine udfordringer Overvind og tjen!",
|
||||||
|
"Your SAS level has upgraded you to {level}!": "Your SAS level has upgraded you to {level}!",
|
||||||
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
||||||
"Your accounts are connected": "Your accounts are connected",
|
"Your accounts are connected": "Your accounts are connected",
|
||||||
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
||||||
|
|||||||
@@ -775,6 +775,7 @@
|
|||||||
"You must accept the terms and conditions": "You must accept the terms and conditions",
|
"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“",
|
"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 Challenges Conquer & Earn!": "Meistern Sie Ihre Herausforderungen und verdienen Sie Geld!",
|
||||||
|
"Your SAS level has upgraded you to {level}!": "Your SAS level has upgraded you to {level}!",
|
||||||
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
||||||
"Your accounts are connected": "Your accounts are connected",
|
"Your accounts are connected": "Your accounts are connected",
|
||||||
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
||||||
|
|||||||
@@ -772,6 +772,7 @@
|
|||||||
"You must accept the terms and conditions": "You must accept the terms and conditions",
|
"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'",
|
"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 Challenges Conquer & Earn!": "Your Challenges Conquer & Earn!",
|
||||||
|
"Your SAS level has upgraded you to {level}!": "Your SAS level has upgraded you to {level}!",
|
||||||
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
||||||
"Your accounts are connected": "Your accounts are connected",
|
"Your accounts are connected": "Your accounts are connected",
|
||||||
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
||||||
|
|||||||
@@ -775,6 +775,7 @@
|
|||||||
"You must accept the terms and conditions": "You must accept the terms and conditions",
|
"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'",
|
"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 Challenges Conquer & Earn!": "Your Challenges Conquer & Earn!",
|
||||||
|
"Your SAS level has upgraded you to {level}!": "Your SAS level has upgraded you to {level}!",
|
||||||
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
||||||
"Your accounts are connected": "Your accounts are connected",
|
"Your accounts are connected": "Your accounts are connected",
|
||||||
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
||||||
|
|||||||
@@ -771,6 +771,7 @@
|
|||||||
"You must accept the terms and conditions": "You must accept the terms and conditions",
|
"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'",
|
"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 Challenges Conquer & Earn!": "Dine utfordringer Erobre og tjen!",
|
||||||
|
"Your SAS level has upgraded you to {level}!": "Your SAS level has upgraded you to {level}!",
|
||||||
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
||||||
"Your accounts are connected": "Your accounts are connected",
|
"Your accounts are connected": "Your accounts are connected",
|
||||||
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
||||||
|
|||||||
@@ -773,6 +773,7 @@
|
|||||||
"You must accept the terms and conditions": "You must accept the terms and conditions",
|
"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'",
|
"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 Challenges Conquer & Earn!": "Dina utmaningar Erövra och tjäna!",
|
||||||
|
"Your SAS level has upgraded you to {level}!": "Your SAS level has upgraded you to {level}!",
|
||||||
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
"Your SAS level has upgraded your friends level": "Your SAS level has upgraded your friends level",
|
||||||
"Your accounts are connected": "Your accounts are connected",
|
"Your accounts are connected": "Your accounts are connected",
|
||||||
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
"Your accounts are now unlinked": "Your accounts are now unlinked",
|
||||||
|
|||||||
@@ -165,8 +165,8 @@ export namespace endpoints {
|
|||||||
export const profile = `${base.path.profile}/${version}/${base.enitity.Profile}`
|
export const profile = `${base.path.profile}/${version}/${base.enitity.Profile}`
|
||||||
export const subscriberId = `${base.path.profile}/${version}/${base.enitity.Profile}/SubscriberId`
|
export const subscriberId = `${base.path.profile}/${version}/${base.enitity.Profile}/SubscriberId`
|
||||||
export const link = `${base.path.profile}/${version}/${base.enitity.Profile}/link`
|
export const link = `${base.path.profile}/${version}/${base.enitity.Profile}/link`
|
||||||
|
|
||||||
export const unlink = `${base.path.profile}/${version}/${base.enitity.Profile}/Unlink`
|
export const unlink = `${base.path.profile}/${version}/${base.enitity.Profile}/Unlink`
|
||||||
|
export const matchTier = `${base.path.profile}/${version}/${base.enitity.Profile}/MatchTier`
|
||||||
|
|
||||||
// TODO: Remove once new endpoints are out in production.
|
// TODO: Remove once new endpoints are out in production.
|
||||||
export const reward = `${base.path.profile}/${version}/${base.enitity.Profile}/reward`
|
export const reward = `${base.path.profile}/${version}/${base.enitity.Profile}/reward`
|
||||||
|
|||||||
@@ -1,21 +1,97 @@
|
|||||||
import { TRPCError } from "@trpc/server"
|
import { cookies } from "next/headers"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import * as api from "@/lib/api"
|
||||||
|
import { getVerifiedUser } from "@/server/routers/user/query"
|
||||||
import { protectedProcedure } from "@/server/trpc"
|
import { protectedProcedure } from "@/server/trpc"
|
||||||
|
|
||||||
import { timeout } from "@/utils/timeout"
|
import { timeout } from "@/utils/timeout"
|
||||||
|
|
||||||
const outputSchema = z.object({})
|
const matchedSchema = z.object({
|
||||||
|
tierMatchState: z.enum(["matched"]),
|
||||||
|
toLevel: z.enum(["L1", "L2", "L3", "L4", "L5", "L6", "L7"]),
|
||||||
|
})
|
||||||
|
const notMatchedSchema = z.object({
|
||||||
|
tierMatchState: z.enum(["alreadyMatched", "notLinked", "error", "cached"]),
|
||||||
|
})
|
||||||
|
|
||||||
|
const outputSchema = z.union([matchedSchema, notMatchedSchema])
|
||||||
|
|
||||||
export const performLevelUpgrade = protectedProcedure
|
export const performLevelUpgrade = protectedProcedure
|
||||||
.output(outputSchema)
|
.output(outputSchema)
|
||||||
.mutation(async function ({ ctx, input }) {
|
.mutation(async function ({ ctx }) {
|
||||||
console.log("[SAS] perform upgrade")
|
console.log("[SAS] tier match")
|
||||||
await timeout(1000)
|
|
||||||
//TODO: Call actual API here
|
|
||||||
|
|
||||||
throw new TRPCError({
|
const cookieStore = cookies()
|
||||||
message: "Unable to perform ugprade",
|
const sasTierMatch = cookieStore.get("sasTierMatch")
|
||||||
code: "BAD_REQUEST",
|
if (sasTierMatch) {
|
||||||
|
return { tierMatchState: "cached" }
|
||||||
|
}
|
||||||
|
|
||||||
|
const userBeforeTierMatch = await getVerifiedUser({
|
||||||
|
session: ctx.session,
|
||||||
})
|
})
|
||||||
|
if (!userBeforeTierMatch || userBeforeTierMatch?.error) {
|
||||||
|
return { tierMatchState: "error" }
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiResponse = await api.post(api.endpoints.v1.Profile.matchTier, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${ctx.session.token.access_token}`,
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
partner: "sas_eb",
|
||||||
|
partnerSpecific: {},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
cookieStore.set("sasTierMatch", "true", {
|
||||||
|
maxAge: 60 * 60 * 24,
|
||||||
|
httpOnly: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (apiResponse.status === 202) {
|
||||||
|
console.log("[SAS] tier match started")
|
||||||
|
|
||||||
|
// Since the tier match is async we need to wait for it to complete before checking the result
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
const userAfterTierMatch = await getVerifiedUser({
|
||||||
|
session: ctx.session,
|
||||||
|
})
|
||||||
|
if (!userAfterTierMatch || userAfterTierMatch?.error) {
|
||||||
|
return { tierMatchState: "error" }
|
||||||
|
}
|
||||||
|
|
||||||
|
const beforeLevel = userBeforeTierMatch.data.membership?.membershipLevel
|
||||||
|
const afterLevel = userAfterTierMatch.data.membership?.membershipLevel
|
||||||
|
|
||||||
|
if (!beforeLevel || !afterLevel) {
|
||||||
|
console.log("[SAS] tier match error, user tier not found")
|
||||||
|
return { tierMatchState: "error" }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beforeLevel !== afterLevel) {
|
||||||
|
console.log(
|
||||||
|
`[SAS] tier match success, user tier changed from ${beforeLevel} to ${afterLevel}`
|
||||||
|
)
|
||||||
|
return { tierMatchState: "matched", toLevel: afterLevel }
|
||||||
|
}
|
||||||
|
|
||||||
|
return { tierMatchState: "alreadyMatched" }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiResponse.status === 204) {
|
||||||
|
console.log("[SAS] tier already matched")
|
||||||
|
return { tierMatchState: "alreadyMatched" }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiResponse.status === 404) {
|
||||||
|
return { tierMatchState: "notLinked" }
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`[SAS] tier match error with status code ${apiResponse.status} and response ${await apiResponse.text()}`
|
||||||
|
)
|
||||||
|
return { tierMatchState: "error" }
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user