From 29f0eb4f21e396bc313191cdb17b32e77d1ccf2c Mon Sep 17 00:00:00 2001 From: Anton Gunnarsson Date: Thu, 13 Mar 2025 14:12:31 +0000 Subject: [PATCH] Merged in feat/sw-1732-trigger-tier-match (pull request #1408) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../app/[lang]/(live)/(public)/login/route.ts | 9 +- .../SAS/LinkedAccounts/LevelUpgradeButton.tsx | 50 ---------- .../levelupgradebutton.module.css | 25 ----- .../MyPages/SASLevelUpgradeCheck.tsx | 62 ++++++++++++ .../components/MyPages/Sidebar/index.tsx | 8 ++ apps/scandic-web/i18n/dictionaries/da.json | 1 + apps/scandic-web/i18n/dictionaries/de.json | 1 + apps/scandic-web/i18n/dictionaries/en.json | 1 + apps/scandic-web/i18n/dictionaries/fi.json | 1 + apps/scandic-web/i18n/dictionaries/no.json | 1 + apps/scandic-web/i18n/dictionaries/sv.json | 1 + apps/scandic-web/lib/api/endpoints.ts | 2 +- .../partners/sas/performLevelUpgrade.ts | 94 +++++++++++++++++-- 13 files changed, 170 insertions(+), 86 deletions(-) delete mode 100644 apps/scandic-web/components/Blocks/DynamicContent/SAS/LinkedAccounts/LevelUpgradeButton.tsx delete mode 100644 apps/scandic-web/components/Blocks/DynamicContent/SAS/LinkedAccounts/levelupgradebutton.module.css create mode 100644 apps/scandic-web/components/MyPages/SASLevelUpgradeCheck.tsx diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts b/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts index 4ee4ce565..8cb3b115f 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts +++ b/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts @@ -117,7 +117,14 @@ export async function GET( /** Record is next-auth typings */ const params: Record = { 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 * page for Scandic. Without the parameter Curity presents some choices diff --git a/apps/scandic-web/components/Blocks/DynamicContent/SAS/LinkedAccounts/LevelUpgradeButton.tsx b/apps/scandic-web/components/Blocks/DynamicContent/SAS/LinkedAccounts/LevelUpgradeButton.tsx deleted file mode 100644 index 661d0c568..000000000 --- a/apps/scandic-web/components/Blocks/DynamicContent/SAS/LinkedAccounts/LevelUpgradeButton.tsx +++ /dev/null @@ -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 ( - <> - - - ) -} diff --git a/apps/scandic-web/components/Blocks/DynamicContent/SAS/LinkedAccounts/levelupgradebutton.module.css b/apps/scandic-web/components/Blocks/DynamicContent/SAS/LinkedAccounts/levelupgradebutton.module.css deleted file mode 100644 index 3f62be530..000000000 --- a/apps/scandic-web/components/Blocks/DynamicContent/SAS/LinkedAccounts/levelupgradebutton.module.css +++ /dev/null @@ -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; - } -} diff --git a/apps/scandic-web/components/MyPages/SASLevelUpgradeCheck.tsx b/apps/scandic-web/components/MyPages/SASLevelUpgradeCheck.tsx new file mode 100644 index 000000000..4951da563 --- /dev/null +++ b/apps/scandic-web/components/MyPages/SASLevelUpgradeCheck.tsx @@ -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 +} diff --git a/apps/scandic-web/components/MyPages/Sidebar/index.tsx b/apps/scandic-web/components/MyPages/Sidebar/index.tsx index f76965e2f..1ee387be7 100644 --- a/apps/scandic-web/components/MyPages/Sidebar/index.tsx +++ b/apps/scandic-web/components/MyPages/Sidebar/index.tsx @@ -1,16 +1,23 @@ import { logout } from "@/constants/routes/handleAuth" +import { getProfileSafely } from "@/lib/trpc/memoizedRequests" import { serverClient } from "@/lib/trpc/server" +import { SASLevelUpgradeCheck } from "@/components/MyPages/SASLevelUpgradeCheck" import Divider from "@/components/TempDesignSystem/Divider" import Link from "@/components/TempDesignSystem/Link" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import { getIntl } from "@/i18n" import { getLang } from "@/i18n/serverContext" +import { getEurobonusMembership } from "@/utils/user" import styles from "./sidebar.module.css" export default async function SidebarMyPages() { const intl = await getIntl() + const profile = await getProfileSafely() + const eurobonusMembership = profile + ? getEurobonusMembership(profile.memberships) + : null return ( ) } diff --git a/apps/scandic-web/i18n/dictionaries/da.json b/apps/scandic-web/i18n/dictionaries/da.json index a3f5017ff..070ade1c4 100644 --- a/apps/scandic-web/i18n/dictionaries/da.json +++ b/apps/scandic-web/i18n/dictionaries/da.json @@ -777,6 +777,7 @@ "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 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 accounts are connected": "Your accounts are connected", "Your accounts are now unlinked": "Your accounts are now unlinked", diff --git a/apps/scandic-web/i18n/dictionaries/de.json b/apps/scandic-web/i18n/dictionaries/de.json index e44c24ded..d12cf2360 100644 --- a/apps/scandic-web/i18n/dictionaries/de.json +++ b/apps/scandic-web/i18n/dictionaries/de.json @@ -775,6 +775,7 @@ "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 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 accounts are connected": "Your accounts are connected", "Your accounts are now unlinked": "Your accounts are now unlinked", diff --git a/apps/scandic-web/i18n/dictionaries/en.json b/apps/scandic-web/i18n/dictionaries/en.json index cf2770526..96eb486c2 100644 --- a/apps/scandic-web/i18n/dictionaries/en.json +++ b/apps/scandic-web/i18n/dictionaries/en.json @@ -772,6 +772,7 @@ "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 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 accounts are connected": "Your accounts are connected", "Your accounts are now unlinked": "Your accounts are now unlinked", diff --git a/apps/scandic-web/i18n/dictionaries/fi.json b/apps/scandic-web/i18n/dictionaries/fi.json index 2c7d6a0a2..af7fe01d3 100644 --- a/apps/scandic-web/i18n/dictionaries/fi.json +++ b/apps/scandic-web/i18n/dictionaries/fi.json @@ -775,6 +775,7 @@ "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 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 accounts are connected": "Your accounts are connected", "Your accounts are now unlinked": "Your accounts are now unlinked", diff --git a/apps/scandic-web/i18n/dictionaries/no.json b/apps/scandic-web/i18n/dictionaries/no.json index 4b280f041..3b9792d25 100644 --- a/apps/scandic-web/i18n/dictionaries/no.json +++ b/apps/scandic-web/i18n/dictionaries/no.json @@ -771,6 +771,7 @@ "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 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 accounts are connected": "Your accounts are connected", "Your accounts are now unlinked": "Your accounts are now unlinked", diff --git a/apps/scandic-web/i18n/dictionaries/sv.json b/apps/scandic-web/i18n/dictionaries/sv.json index 8cca7ea8f..8768a00b5 100644 --- a/apps/scandic-web/i18n/dictionaries/sv.json +++ b/apps/scandic-web/i18n/dictionaries/sv.json @@ -773,6 +773,7 @@ "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 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 accounts are connected": "Your accounts are connected", "Your accounts are now unlinked": "Your accounts are now unlinked", diff --git a/apps/scandic-web/lib/api/endpoints.ts b/apps/scandic-web/lib/api/endpoints.ts index 09eca0555..4107f3854 100644 --- a/apps/scandic-web/lib/api/endpoints.ts +++ b/apps/scandic-web/lib/api/endpoints.ts @@ -165,8 +165,8 @@ export namespace endpoints { export const profile = `${base.path.profile}/${version}/${base.enitity.Profile}` export const subscriberId = `${base.path.profile}/${version}/${base.enitity.Profile}/SubscriberId` export const link = `${base.path.profile}/${version}/${base.enitity.Profile}/link` - 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. export const reward = `${base.path.profile}/${version}/${base.enitity.Profile}/reward` diff --git a/apps/scandic-web/server/routers/partners/sas/performLevelUpgrade.ts b/apps/scandic-web/server/routers/partners/sas/performLevelUpgrade.ts index 7e2a9f2e0..0956c0020 100644 --- a/apps/scandic-web/server/routers/partners/sas/performLevelUpgrade.ts +++ b/apps/scandic-web/server/routers/partners/sas/performLevelUpgrade.ts @@ -1,21 +1,97 @@ -import { TRPCError } from "@trpc/server" +import { cookies } from "next/headers" import { z } from "zod" +import * as api from "@/lib/api" +import { getVerifiedUser } from "@/server/routers/user/query" import { protectedProcedure } from "@/server/trpc" 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 .output(outputSchema) - .mutation(async function ({ ctx, input }) { - console.log("[SAS] perform upgrade") - await timeout(1000) - //TODO: Call actual API here + .mutation(async function ({ ctx }) { + console.log("[SAS] tier match") - throw new TRPCError({ - message: "Unable to perform ugprade", - code: "BAD_REQUEST", + const cookieStore = cookies() + const sasTierMatch = cookieStore.get("sasTierMatch") + 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" } })