Merged in feat/LOY-484-consent-alert (pull request #3184)

feat(LOY-484): Change toast to alert for Profiling Consent

* feat(LOY-484): change toast to alert using context

* refactor(LOY-484): remove uneccesary code

* chore(LOY-484): small UI fixes


Approved-by: Chuma Mcphoy (We Ahead)
This commit is contained in:
Matilda Landström
2025-11-26 12:13:04 +00:00
parent 086319e8b1
commit 26f3b5bdd0
6 changed files with 173 additions and 38 deletions

View File

@@ -6,6 +6,8 @@ import {
getProfilingConsent,
} from "@/lib/trpc/memoizedRequests"
import ProfilingConsentAlert from "@/components/MyPages/ProfilingConsent/Alert"
import { ProfilingConsentAlertProvider } from "@/components/MyPages/ProfilingConsent/Alert/AlertContext"
import ProfilingConsentModal from "@/components/MyPages/ProfilingConsent/Modal"
import { userHasConsent } from "@/components/MyPages/ProfilingConsent/utils"
import { SASLevelUpgradeCheck } from "@/components/MyPages/SASLevelUpgradeCheck"
@@ -36,24 +38,32 @@ export default async function MyPagesLayout({
const lang = await getLang()
return (
<div className={styles.container}>
<div className={styles.layout}>
{breadcrumbs}
<div className={styles.content}>{children}</div>
</div>
<ProfilingConsentAlertProvider>
<div className={styles.container}>
<div className={styles.layout}>
{breadcrumbs}
{eurobonusMembership && <SASLevelUpgradeCheck />}
<Surprises />
{memberKey && profilingConsent && !hasConsent ? (
<>
<ProfilingConsentModal
memberKey={memberKey}
content={profilingConsent.modal}
iconIdentifier={profilingConsent.icon}
/>
<TrackingSDK pageData={{ domainLanguage: lang, ...ModalTracking }} />
</>
) : null}
</div>
<div className={styles.content}>
<ProfilingConsentAlert />
{children}
</div>
</div>
{eurobonusMembership && <SASLevelUpgradeCheck />}
<Surprises />
{memberKey && profilingConsent && !hasConsent ? (
<>
<ProfilingConsentModal
memberKey={memberKey}
content={profilingConsent.modal}
iconIdentifier={profilingConsent.icon}
/>
<TrackingSDK
pageData={{ domainLanguage: lang, ...ModalTracking }}
/>
</>
) : null}
</div>
</ProfilingConsentAlertProvider>
)
}

View File

@@ -8,6 +8,8 @@
padding: var(--Space-x4) var(--Space-x2) 0;
display: grid;
gap: var(--Space-x6);
border-radius: var(--Corner-radius-Medium) var(--Corner-radius-Medium) 0 0;
}
.buttons {
@@ -20,6 +22,12 @@
padding: var(--Space-x2) var(--Space-x3) var(--Space-x3) var(--Space-x3);
border-top: 1px solid var(--Border-Divider-Subtle);
background: var(--Base-Surface-Primary-light-Normal);
border-radius: 0 0 var(--Corner-radius-Medium) var(--Corner-radius-Medium);
button {
width: 100%;
}
}
.title {
@@ -48,11 +56,19 @@
.form {
padding: var(--Space-x4) var(--Space-x3) 0;
gap: var(--Space-x6);
border-radius: 0;
}
.buttons {
flex-direction: row-reverse;
gap: var(--Space-x2);
padding: var(--Space-x6) var(--Space-x3) var(--Space-x4);
border-radius: 0;
button {
width: auto;
}
}
}

View File

@@ -0,0 +1,30 @@
"use client"
import { createContext, type ReactNode, useContext, useState } from "react"
import type { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
type AlertType = AlertTypeEnum.Success | AlertTypeEnum.Alarm
const ProfilingConsentAlertContext = createContext<{
alertType: AlertType | null
setAlertType: (data: AlertType | null) => void
}>({
alertType: null,
setAlertType: () => {},
})
export function ProfilingConsentAlertProvider({
children,
}: {
children: ReactNode
}) {
const [alertType, setAlertType] = useState<AlertType | null>(null)
return (
<ProfilingConsentAlertContext.Provider value={{ alertType, setAlertType }}>
{children}
</ProfilingConsentAlertContext.Provider>
)
}
export const useProfilingConsentAlert = () =>
useContext(ProfilingConsentAlertContext)

View File

@@ -0,0 +1,4 @@
.alert {
height: fit-content;
margin-bottom: var(--Space-x1);
}

View File

@@ -0,0 +1,86 @@
"use client"
import { type IntlShape, useIntl } from "react-intl"
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import { profileConsent } from "@scandic-hotels/common/constants/routes/myPages"
import { Alert } from "@scandic-hotels/design-system/Alert"
import useLang from "@/hooks/useLang"
import { useProfilingConsentAlert } from "./AlertContext"
import styles from "./alert.module.css"
import type { Lang } from "@scandic-hotels/common/constants/language"
type AlertData = {
type: AlertTypeEnum.Success | AlertTypeEnum.Alarm
heading: string
message?: string
link?: { url: string; title: string }
}
export default function ProfilingConsentAlert() {
const { alertType, setAlertType } = useProfilingConsentAlert()
const intl = useIntl()
const lang = useLang()
if (!alertType) return null
const alert = getAlert(alertType, intl, lang)
if (!alert) return null
return (
<Alert
variant="inline"
type={alert.type}
heading={alert.heading}
link={alert.link}
text={alert.message}
close={() => setAlertType(null)}
className={styles.alert}
/>
)
}
function getAlert(
alertType: AlertTypeEnum,
intl: IntlShape,
lang: Lang
): AlertData | null {
switch (alertType) {
case AlertTypeEnum.Success:
return {
type: AlertTypeEnum.Success,
heading: intl.formatMessage({
id: "profilingConsent.alert.preferenceSaved",
defaultMessage: "Preference saved!",
}),
link: {
url: profileConsent[lang],
title: intl.formatMessage({
id: "profilingConsent.alert.editIn",
defaultMessage: "Edit in Personalization & Profiling",
}),
},
}
case AlertTypeEnum.Alarm:
return {
type: AlertTypeEnum.Alarm,
heading: intl.formatMessage({
id: "profilingConsent.alert.preferenceNotSaved",
defaultMessage: "Preference not saved!",
}),
message: intl.formatMessage({
id: "profilingConsent.alert.anErrorOcurred",
defaultMessage:
"An error occurred when updating preferences, please try again later.",
}),
}
default:
return null
}
}

View File

@@ -1,38 +1,27 @@
"use client"
import { useRouter } from "next/navigation"
import { useIntl } from "react-intl"
import { toast } from "@scandic-hotels/design-system/Toast"
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import { trpc } from "@scandic-hotels/trpc/client"
import { useProfilingConsentAlert } from "@/components/MyPages/ProfilingConsent/Alert/AlertContext"
export function useUpdateProfilingConsent() {
const intl = useIntl()
const utils = trpc.useUtils()
const router = useRouter()
const { setAlertType } = useProfilingConsentAlert()
const updateConsent = trpc.user.profilingConsent.update.useMutation({
onSuccess: async () => {
await utils.user.get.invalidate()
router.refresh()
setTimeout(() => {
toast.success(
intl.formatMessage({
id: "profilingConsent.alert.updateConsentSuccessful",
defaultMessage: "Preference saved!",
})
)
})
setAlertType(AlertTypeEnum.Success)
},
onError: () => {
setTimeout(() => {
toast.error(
intl.formatMessage({
id: "profilingConsent.alert.updateConsentFailed",
defaultMessage:
"An error occurred when updating preferences, please try again later.",
})
)
})
setAlertType(AlertTypeEnum.Alarm)
},
})