feat: add communication preferences

feat: add generatePreferencesLink

feat: add subscriberId endpoint
This commit is contained in:
Christel Westerberg
2024-09-19 14:07:45 +02:00
parent 676b763e67
commit 2886084a82
17 changed files with 158 additions and 13 deletions

View File

@@ -19,6 +19,8 @@ DESIGN_SYSTEM_ACCESS_TOKEN=""
NEXTAUTH_REDIRECT_PROXY_URL="http://localhost:3000/api/web/auth" NEXTAUTH_REDIRECT_PROXY_URL="http://localhost:3000/api/web/auth"
NEXTAUTH_SECRET="" NEXTAUTH_SECRET=""
REVALIDATE_SECRET="" REVALIDATE_SECRET=""
SALESFORCE_PREFRENCE_BASE_URL="https://mc31njyvc80x-2b9wg-24jxcj5yq.pub.sfmc-content.com/disfelgm4fv"
SEAMLESS_LOGIN_DA="http://www.example.dk/updatelogin" SEAMLESS_LOGIN_DA="http://www.example.dk/updatelogin"
SEAMLESS_LOGIN_DE="http://www.example.de/updatelogin" SEAMLESS_LOGIN_DE="http://www.example.de/updatelogin"
SEAMLESS_LOGIN_EN="http://www.example.com/updatelogin" SEAMLESS_LOGIN_EN="http://www.example.com/updatelogin"

View File

@@ -1,4 +1,5 @@
import { ArrowRightIcon } from "@/components/Icons" import { ArrowRightIcon } from "@/components/Icons"
import ManagePreferencesButton from "@/components/Profile/ManagePreferencesButton"
import Link from "@/components/TempDesignSystem/Link" import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body" import Body from "@/components/TempDesignSystem/Text/Body"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
@@ -27,12 +28,7 @@ export default async function CommunicationSlot({
})} })}
</Body> </Body>
</article> </article>
<Link href="#" variant="icon"> <ManagePreferencesButton />
<ArrowRightIcon color="burgundy" />
<Body color="burgundy" textTransform="underlined">
{formatMessage({ id: "Manage preferences" })}
</Body>
</Link>
</section> </section>
) )
} }

View File

@@ -1,4 +1,3 @@
import { env } from "@/env/server"
import { serverClient } from "@/lib/trpc/server" import { serverClient } from "@/lib/trpc/server"
import AddCreditCardButton from "@/components/Profile/AddCreditCardButton" import AddCreditCardButton from "@/components/Profile/AddCreditCardButton"
@@ -17,8 +16,6 @@ export default async function CreditCardSlot({ params }: PageArgs<LangParams>) {
const { formatMessage } = await getIntl() const { formatMessage } = await getIntl()
const creditCards = await serverClient().user.creditCards() const creditCards = await serverClient().user.creditCards()
const { lang } = params
return ( return (
<section className={styles.container}> <section className={styles.container}>
<article className={styles.content}> <article className={styles.content}>

View File

@@ -15,8 +15,7 @@ export default function ProfileLayout({
{profile} {profile}
<Divider color="burgundy" opacity={8} /> <Divider color="burgundy" opacity={8} />
{creditCards} {creditCards}
{/* TODO: Implement communication preferences flow. Hidden until decided on where to send user. */} {communication}
{/* {communication} */}
</section> </section>
</main> </main>
) )

View File

@@ -0,0 +1,51 @@
"use client"
import { useIntl } from "react-intl"
import { trpc } from "@/lib/trpc/client"
import ArrowRight from "@/components/Icons/ArrowRight"
import Button from "@/components/TempDesignSystem/Button"
import { toast } from "@/components/TempDesignSystem/Toasts"
import styles from "./managePreferencesButton.module.css"
export default function ManagePreferencesButton() {
const intl = useIntl()
const generatePreferencesLink = trpc.user.generatePreferencesLink.useMutation(
{
onSuccess: (preferencesLink) => {
if (preferencesLink) {
window.open(preferencesLink, "_blank")
} else {
toast.error(
intl.formatMessage({
id: "It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.",
})
)
}
},
onError: (e) => {
toast.error(
intl.formatMessage({
id: "An error occurred trying to manage your preferences, please try again later.",
})
)
},
}
)
return (
<Button
className={styles.managePreferencesButton}
variant="icon"
theme="base"
intent="text"
onClick={() => generatePreferencesLink.mutate()}
wrapping
>
<ArrowRight color="burgundy" />
{intl.formatMessage({ id: "Manage preferences" })}
</Button>
)
}

View File

@@ -0,0 +1,3 @@
.managePreferencesButton {
justify-self: flex-start;
}

2
env/server.ts vendored
View File

@@ -47,6 +47,7 @@ export const env = createEnv({
.default("false"), .default("false"),
PUBLIC_URL: z.string().optional(), PUBLIC_URL: z.string().optional(),
REVALIDATE_SECRET: z.string(), REVALIDATE_SECRET: z.string(),
SALESFORCE_PREFRENCE_BASE_URL: z.string(),
SEAMLESS_LOGIN_DA: z.string(), SEAMLESS_LOGIN_DA: z.string(),
SEAMLESS_LOGIN_DE: z.string(), SEAMLESS_LOGIN_DE: z.string(),
SEAMLESS_LOGIN_EN: z.string(), SEAMLESS_LOGIN_EN: z.string(),
@@ -104,6 +105,7 @@ export const env = createEnv({
PRINT_QUERY: process.env.PRINT_QUERY, PRINT_QUERY: process.env.PRINT_QUERY,
PUBLIC_URL: process.env.PUBLIC_URL, PUBLIC_URL: process.env.PUBLIC_URL,
REVALIDATE_SECRET: process.env.REVALIDATE_SECRET, REVALIDATE_SECRET: process.env.REVALIDATE_SECRET,
SALESFORCE_PREFRENCE_BASE_URL: process.env.SALESFORCE_PREFRENCE_BASE_URL,
SEAMLESS_LOGIN_DA: process.env.SEAMLESS_LOGIN_DA, SEAMLESS_LOGIN_DA: process.env.SEAMLESS_LOGIN_DA,
SEAMLESS_LOGIN_DE: process.env.SEAMLESS_LOGIN_DE, SEAMLESS_LOGIN_DE: process.env.SEAMLESS_LOGIN_DE,
SEAMLESS_LOGIN_EN: process.env.SEAMLESS_LOGIN_EN, SEAMLESS_LOGIN_EN: process.env.SEAMLESS_LOGIN_EN,

View File

@@ -10,6 +10,7 @@
"Amenities": "Faciliteter", "Amenities": "Faciliteter",
"Amusement park": "Forlystelsespark", "Amusement park": "Forlystelsespark",
"An error occurred when adding a credit card, please try again later.": "Der opstod en fejl under tilføjelse af et kreditkort. Prøv venligst igen senere.", "An error occurred when adding a credit card, please try again later.": "Der opstod en fejl under tilføjelse af et kreditkort. Prøv venligst igen senere.",
"An error occurred trying to manage your preferences, please try again later.": "Der opstod en fejl under forsøget på at administrere dine præferencer. Prøv venligst igen senere.",
"An error occurred when trying to update profile.": "Der opstod en fejl under forsøg på at opdatere profilen.", "An error occurred when trying to update profile.": "Der opstod en fejl under forsøg på at opdatere profilen.",
"Any changes you've made will be lost.": "Alle ændringer, du har foretaget, går tabt.", "Any changes you've made will be lost.": "Alle ændringer, du har foretaget, går tabt.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Er du sikker på, at du vil fjerne kortet, der slutter me {lastFourDigits} fra din medlemsprofil?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Er du sikker på, at du vil fjerne kortet, der slutter me {lastFourDigits} fra din medlemsprofil?",
@@ -99,6 +100,7 @@
"How do you want to sleep?": "Hvordan vil du sove?", "How do you want to sleep?": "Hvordan vil du sove?",
"How it works": "Hvordan det virker", "How it works": "Hvordan det virker",
"Image gallery": "Billedgalleri", "Image gallery": "Billedgalleri",
"It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "Det er ikke muligt at administrere dine kommunikationspræferencer lige nu, prøv venligst igen senere eller kontakt support, hvis problemet fortsætter.",
"Join Scandic Friends": "Tilmeld dig Scandic Friends", "Join Scandic Friends": "Tilmeld dig Scandic Friends",
"Join at no cost": "Tilmeld dig uden omkostninger", "Join at no cost": "Tilmeld dig uden omkostninger",
"Language": "Sprog", "Language": "Sprog",

View File

@@ -10,6 +10,7 @@
"Amenities": "Annehmlichkeiten", "Amenities": "Annehmlichkeiten",
"Amusement park": "Vergnügungspark", "Amusement park": "Vergnügungspark",
"An error occurred when adding a credit card, please try again later.": "Beim Hinzufügen einer Kreditkarte ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.", "An error occurred when adding a credit card, please try again later.": "Beim Hinzufügen einer Kreditkarte ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.",
"An error occurred trying to manage your preferences, please try again later.": "Beim Versuch, Ihre Einstellungen zu verwalten, ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.",
"An error occurred when trying to update profile.": "Beim Versuch, das Profil zu aktualisieren, ist ein Fehler aufgetreten.", "An error occurred when trying to update profile.": "Beim Versuch, das Profil zu aktualisieren, ist ein Fehler aufgetreten.",
"Any changes you've made will be lost.": "Alle Änderungen, die Sie vorgenommen haben, gehen verloren.", "Any changes you've made will be lost.": "Alle Änderungen, die Sie vorgenommen haben, gehen verloren.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Möchten Sie die Karte mit der Endung {lastFourDigits} wirklich aus Ihrem Mitgliedsprofil entfernen?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Möchten Sie die Karte mit der Endung {lastFourDigits} wirklich aus Ihrem Mitgliedsprofil entfernen?",
@@ -104,6 +105,7 @@
"How do you want to sleep?": "Wie möchtest du schlafen?", "How do you want to sleep?": "Wie möchtest du schlafen?",
"How it works": "Wie es funktioniert", "How it works": "Wie es funktioniert",
"Image gallery": "Bildergalerie", "Image gallery": "Bildergalerie",
"It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "Es ist derzeit nicht möglich, Ihre Kommunikationseinstellungen zu verwalten. Bitte versuchen Sie es später erneut oder wenden Sie sich an den Support, wenn das Problem weiterhin besteht.",
"Join Scandic Friends": "Treten Sie Scandic Friends bei", "Join Scandic Friends": "Treten Sie Scandic Friends bei",
"km to city center": "km bis zum Stadtzentrum", "km to city center": "km bis zum Stadtzentrum",
"Language": "Sprache", "Language": "Sprache",

View File

@@ -10,6 +10,7 @@
"Amenities": "Amenities", "Amenities": "Amenities",
"Amusement park": "Amusement park", "Amusement park": "Amusement park",
"An error occurred when adding a credit card, please try again later.": "An error occurred when adding a credit card, please try again later.", "An error occurred when adding a credit card, please try again later.": "An error occurred when adding a credit card, please try again later.",
"An error occurred trying to manage your preferences, please try again later.": "An error occurred trying to manage your preferences, please try again later.",
"An error occurred when trying to update profile.": "An error occurred when trying to update profile.", "An error occurred when trying to update profile.": "An error occurred when trying to update profile.",
"Any changes you've made will be lost.": "Any changes you've made will be lost.", "Any changes you've made will be lost.": "Any changes you've made will be lost.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?",
@@ -103,6 +104,7 @@
"How do you want to sleep?": "How do you want to sleep?", "How do you want to sleep?": "How do you want to sleep?",
"How it works": "How it works", "How it works": "How it works",
"Image gallery": "Image gallery", "Image gallery": "Image gallery",
"It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.",
"Join Scandic Friends": "Join Scandic Friends", "Join Scandic Friends": "Join Scandic Friends",
"Join at no cost": "Join at no cost", "Join at no cost": "Join at no cost",
"Language": "Language", "Language": "Language",

View File

@@ -10,6 +10,7 @@
"Amenities": "Mukavuudet", "Amenities": "Mukavuudet",
"Amusement park": "Huvipuisto", "Amusement park": "Huvipuisto",
"An error occurred when adding a credit card, please try again later.": "Luottokorttia lisättäessä tapahtui virhe. Yritä myöhemmin uudelleen.", "An error occurred when adding a credit card, please try again later.": "Luottokorttia lisättäessä tapahtui virhe. Yritä myöhemmin uudelleen.",
"An error occurred trying to manage your preferences, please try again later.": "Asetusten hallinnassa tapahtui virhe. Yritä myöhemmin uudelleen.",
"An error occurred when trying to update profile.": "Profiilia päivitettäessä tapahtui virhe.", "An error occurred when trying to update profile.": "Profiilia päivitettäessä tapahtui virhe.",
"Any changes you've made will be lost.": "Kaikki tekemäsi muutokset menetetään.", "Any changes you've made will be lost.": "Kaikki tekemäsi muutokset menetetään.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Haluatko varmasti poistaa kortin, joka päättyy numeroon {lastFourDigits} jäsenprofiilistasi?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Haluatko varmasti poistaa kortin, joka päättyy numeroon {lastFourDigits} jäsenprofiilistasi?",
@@ -99,6 +100,7 @@
"How do you want to sleep?": "Kuinka haluat nukkua?", "How do you want to sleep?": "Kuinka haluat nukkua?",
"How it works": "Kuinka se toimii", "How it works": "Kuinka se toimii",
"Image gallery": "Kuvagalleria", "Image gallery": "Kuvagalleria",
"It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "Viestintäasetuksiasi ei voi hallita juuri nyt. Yritä myöhemmin uudelleen tai ota yhteyttä tukeen, jos ongelma jatkuu.",
"Join Scandic Friends": "Liity jäseneksi", "Join Scandic Friends": "Liity jäseneksi",
"Join at no cost": "Liity maksutta", "Join at no cost": "Liity maksutta",
"Language": "Kieli", "Language": "Kieli",

View File

@@ -10,6 +10,7 @@
"Amenities": "Fasiliteter", "Amenities": "Fasiliteter",
"Amusement park": "Tivoli", "Amusement park": "Tivoli",
"An error occurred when adding a credit card, please try again later.": "Det oppstod en feil ved å legge til et kredittkort. Prøv igjen senere.", "An error occurred when adding a credit card, please try again later.": "Det oppstod en feil ved å legge til et kredittkort. Prøv igjen senere.",
"An error occurred trying to manage your preferences, please try again later.": "Det oppstod en feil under forsøket på å administrere innstillingene dine. Prøv igjen senere.",
"An error occurred when trying to update profile.": "Det oppstod en feil under forsøk på å oppdatere profilen.", "An error occurred when trying to update profile.": "Det oppstod en feil under forsøk på å oppdatere profilen.",
"Any changes you've made will be lost.": "Eventuelle endringer du har gjort, går tapt.", "Any changes you've made will be lost.": "Eventuelle endringer du har gjort, går tapt.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Er du sikker på at du vil fjerne kortet som slutter på {lastFourDigits} fra medlemsprofilen din?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Er du sikker på at du vil fjerne kortet som slutter på {lastFourDigits} fra medlemsprofilen din?",
@@ -99,6 +100,7 @@
"How do you want to sleep?": "Hvordan vil du sove?", "How do you want to sleep?": "Hvordan vil du sove?",
"How it works": "Hvordan det fungerer", "How it works": "Hvordan det fungerer",
"Image gallery": "Bildegalleri", "Image gallery": "Bildegalleri",
"It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "Det er ikke mulig å administrere kommunikasjonspreferansene dine akkurat nå, prøv igjen senere eller kontakt support hvis problemet vedvarer.",
"Join Scandic Friends": "Bli med i Scandic Friends", "Join Scandic Friends": "Bli med i Scandic Friends",
"Join at no cost": "Bli med uten kostnad", "Join at no cost": "Bli med uten kostnad",
"Language": "Språk", "Language": "Språk",

View File

@@ -10,6 +10,7 @@
"Amenities": "Bekvämligheter", "Amenities": "Bekvämligheter",
"Amusement park": "Nöjespark", "Amusement park": "Nöjespark",
"An error occurred when adding a credit card, please try again later.": "Ett fel uppstod när ett kreditkort lades till, försök igen senare.", "An error occurred when adding a credit card, please try again later.": "Ett fel uppstod när ett kreditkort lades till, försök igen senare.",
"An error occurred trying to manage your preferences, please try again later.": "Ett fel uppstod när du försökte hantera dina inställningar, försök igen senare.",
"An error occurred when trying to update profile.": "Ett fel uppstod när du försökte uppdatera profilen.", "An error occurred when trying to update profile.": "Ett fel uppstod när du försökte uppdatera profilen.",
"Any changes you've made will be lost.": "Alla ändringar du har gjort kommer att gå förlorade.", "Any changes you've made will be lost.": "Alla ändringar du har gjort kommer att gå förlorade.",
"Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Är du säker på att du vill ta bort kortet som slutar med {lastFourDigits} från din medlemsprofil?", "Are you sure you want to remove the card ending with {lastFourDigits} from your member profile?": "Är du säker på att du vill ta bort kortet som slutar med {lastFourDigits} från din medlemsprofil?",
@@ -99,6 +100,8 @@
"How do you want to sleep?": "Hur vill du sova?", "How do you want to sleep?": "Hur vill du sova?",
"How it works": "Hur det fungerar", "How it works": "Hur det fungerar",
"Image gallery": "Bildgalleri", "Image gallery": "Bildgalleri",
"It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "Det gick inte att hantera dina kommunikationsinställningar just nu, försök igen senare eller kontakta supporten om problemet kvarstår.",
"Join Scandic Friends": "Gå med i Scandic Friends", "Join Scandic Friends": "Gå med i Scandic Friends",
"Join at no cost": "Gå med utan kostnad", "Join at no cost": "Gå med utan kostnad",
"Language": "Språk", "Language": "Språk",

View File

@@ -21,6 +21,9 @@ export namespace endpoints {
upcomingStays = "booking/v1/Stays/future", upcomingStays = "booking/v1/Stays/future",
rewards = `${profile}/reward`, rewards = `${profile}/reward`,
tierRewards = `${profile}/TierRewards`, tierRewards = `${profile}/TierRewards`,
intiateSaveCard = `${creditCards}/initiateSaveCard`,
deleteCreditCard = `${profile}/creditCards`,
subscriberId = `${profile}/SubscriberId`,
} }
} }

2
next-env.d.ts vendored
View File

@@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information. // see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.

View File

@@ -1,5 +1,11 @@
import { metrics } from "@opentelemetry/api"
import { env } from "@/env/server"
import * as api from "@/lib/api" import * as api from "@/lib/api"
import { initiateSaveCardSchema } from "@/server/routers/user/output" import {
initiateSaveCardSchema,
subscriberIdSchema,
} from "@/server/routers/user/output"
import { protectedProcedure, router } from "@/server/trpc" import { protectedProcedure, router } from "@/server/trpc"
import { import {
@@ -8,6 +14,17 @@ import {
saveCreditCardInput, saveCreditCardInput,
} from "./input" } from "./input"
const meter = metrics.getMeter("trpc.user")
const generatePreferencesLinkCounter = meter.createCounter(
"trpc.user.generatePreferencesLink"
)
const generatePreferencesLinkSuccessCounter = meter.createCounter(
"trpc.user.generatePreferencesLink-success"
)
const generatePreferencesLinkFailCounter = meter.createCounter(
"trpc.user.generatePreferencesLink-fail"
)
export const userMutationRouter = router({ export const userMutationRouter = router({
creditCard: router({ creditCard: router({
add: protectedProcedure.input(addCreditCardInput).mutation(async function ({ add: protectedProcedure.input(addCreditCardInput).mutation(async function ({
@@ -128,4 +145,62 @@ export const userMutationRouter = router({
return true return true
}), }),
}), }),
generatePreferencesLink: protectedProcedure.mutation(async function ({
ctx,
}) {
generatePreferencesLinkCounter.add(1)
const apiResponse = await api.get(api.endpoints.v1.subscriberId, {
headers: {
Authorization: `Bearer ${ctx.session.token.access_token}`,
},
})
if (!apiResponse.ok) {
const text = await apiResponse.text()
generatePreferencesLinkFailCounter.add(1, {
error_type: "http_error",
error: JSON.stringify({
status: apiResponse.status,
statusText: apiResponse.statusText,
text,
}),
})
console.error(
"api.user.subscriberId error ",
JSON.stringify({
error: {
status: apiResponse.status,
statusText: apiResponse.statusText,
text,
},
})
)
return null
}
const data = await apiResponse.json()
const validatedData = subscriberIdSchema.safeParse(data)
if (!validatedData.success) {
generatePreferencesLinkSuccessCounter.add(1, {
error_type: "validation_error",
error: JSON.stringify(validatedData.error),
})
console.error(
"api.user.generatePreferencesLink validation error",
JSON.stringify({
error: validatedData.error,
})
)
console.error(validatedData.error.format())
return null
}
const preferencesLink = new URL(env.SALESFORCE_PREFRENCE_BASE_URL)
preferencesLink.searchParams.set("subKey", validatedData.data.subscriberId)
generatePreferencesLinkSuccessCounter.add(1)
return preferencesLink.toString()
}),
}) })

View File

@@ -234,3 +234,7 @@ export const initiateSaveCardSchema = z.object({
type: z.string(), type: z.string(),
}), }),
}) })
export const subscriberIdSchema = z.object({
subscriberId: z.string(),
})