Merged in feat/LOY-490-cleanup-profiling-consent (pull request #3237)

Feat/LOY-490 cleanup profiling consent

* chore(LOY-490): cleanup accordion

* xhore(LOY-490): cleanup signup

* fix(LOY-490): use correct tokens

* fi(LOY-490): change button to correct color

* fix(LOY-490): switch deprecated Link


Approved-by: Chuma Mcphoy (We Ahead)
This commit is contained in:
Matilda Landström
2025-11-27 07:48:34 +00:00
parent 42b039c4ef
commit b122f2ff4f
8 changed files with 39 additions and 338 deletions

View File

@@ -2,23 +2,18 @@
import { useIntl } from "react-intl"
import { privacy } from "@scandic-hotels/common/constants/routes/customerService"
import Accordion from "@scandic-hotels/design-system/Accordion"
import AccordionItem from "@scandic-hotels/design-system/Accordion/AccordionItem"
import { IconByIconName } from "@scandic-hotels/design-system/Icons/IconByIconName"
import { IconName } from "@scandic-hotels/design-system/Icons/iconName"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { TextLink } from "@scandic-hotels/design-system/TextLink"
import { Typography } from "@scandic-hotels/design-system/Typography"
import useLang from "@/hooks/useLang"
import { trackLinkClick } from "@/utils/tracking/profilingConsent"
import { getLegalText } from "./personalizationLegalText"
import styles from "./profilingConsentAccordion.module.css"
interface ProfilingConsentAccordionProps {
export interface ProfilingConsentAccordionProps {
component: "modal" | "profile"
}
export default function ProfilingConsentAccordion({
@@ -27,216 +22,8 @@ export default function ProfilingConsentAccordion({
const intl = useIntl()
const lang = useLang()
const dataWeProcess = [
{
icon: IconName.Person,
title: intl.formatMessage({
id: "profilingConsent.NameAndContactInformation",
defaultMessage: "Name and contact information",
}),
subtitle: intl.formatMessage({
id: "profilingConsent.NameEmailPhoneAddress",
defaultMessage:
"Your name, email address, phone number and postal address",
}),
},
{
icon: IconName.Luggage,
title: intl.formatMessage({
id: "profilingConsent.YourBookingsWithScandic",
defaultMessage: "Your bookings with Scandic",
}),
subtitle: intl.formatMessage({
id: "profilingConsent.BookingsDatesDestinationsPreferences",
defaultMessage: "Hotel bookings, dates, destinations and preferences",
}),
},
{
icon: IconName.Diamond,
title: intl.formatMessage({
id: "profilingConsent.YourMembershipInformation",
defaultMessage: "Your membership information",
}),
subtitle: intl.formatMessage({
id: "profilingConsent.ScandicFriendsPointsBenefits",
defaultMessage: "Scandic Friends status, points and member benefits",
}),
},
{
icon: IconName.Business,
title: intl.formatMessage({
id: "profilingConsent.CompanyInformation",
defaultMessage: "Company information",
}),
subtitle: intl.formatMessage({
id: "profilingConsent.InformationAboutYourCompany",
defaultMessage:
"Information about the company you work for (if available)",
}),
},
{
icon: IconName.Globe,
title: intl.formatMessage({
id: "profilingConsent.UserGeneratedData",
defaultMessage: "User-generated data",
}),
subtitle: intl.formatMessage({
id: "profilingConsent.ClicksBrowsingPurchasingInteractions",
defaultMessage:
"Clicks, browsing, purchase history and website interactions",
}),
},
]
const rights = [
intl.formatMessage({
id: "profilingConsent.GetInformation",
defaultMessage: "Get information about how we process your data",
}),
intl.formatMessage({
id: "profilingConsent.RequestDeletion",
defaultMessage: "Request deletion of your personal data",
}),
intl.formatMessage({
id: "profilingConsent.WithdrawConsent",
defaultMessage: "Withdraw your consent at any time",
}),
]
const security = [
intl.formatMessage({
id: "profilingConsent.EncryptedSecureDataStorage",
defaultMessage: "Encrypted & secure data storage",
}),
intl.formatMessage({
id: "profilingConsent.WeWillNeverSellYourData",
defaultMessage: "We will never sell your data",
}),
intl.formatMessage({
id: "profilingConsent.RegularSecurityAudits",
defaultMessage: "Regular security audits",
}),
intl.formatMessage({
id: "profilingConsent.GDPRCompliantProcessing",
defaultMessage: "GDPR-compliant processing",
}),
]
return (
<Accordion type="sidepeek" className={styles.accordion}>
<AccordionItem
title={intl.formatMessage({
id: "profilingConsent.whatDoWeProcess",
defaultMessage: "What data do we process?",
})}
iconName={IconName.InfoCircle}
className={styles.accordionItem}
openedOnRender
>
<ul className={styles.list}>
{dataWeProcess.map((item, i) => (
<li key={i} className={styles.row}>
<span className={styles.rowIcon} aria-hidden>
<IconByIconName
iconName={item.icon}
color="Icon/Interactive/Default"
size={24}
/>
</span>
<span className={styles.rowText}>
<Typography variant="Body/Paragraph/mdBold">
<p>{item.title}</p>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>{item.subtitle}</p>
</Typography>
</span>
</li>
))}
</ul>
</AccordionItem>
<AccordionItem
title={intl.formatMessage({
id: "profilingConsent.transparency&processing",
defaultMessage: "Transparency & data processing",
})}
iconName={IconName.EyeShow}
className={styles.accordionItem}
openedOnRender
>
<div className={styles.columns}>
<div className={styles.column}>
<Typography variant="Title/Subtitle/md">
<h4>
{intl.formatMessage({
id: "profilingConsent.youHaveTheRightTo",
defaultMessage: "You have the right to",
})}
</h4>
</Typography>
<ul className={styles.bullets}>
{rights.map((text, i) => (
<li key={i} className={styles.bulletRow}>
<MaterialIcon
icon="favorite"
size={20}
color="Icon/Accent"
isFilled
/>
<Typography variant="Body/Paragraph/mdRegular">
<p>{text}</p>
</Typography>
</li>
))}
</ul>
</div>
<div className={styles.column}>
<Typography variant="Title/Subtitle/md">
<h4>
{intl.formatMessage({
id: "profilingConsent.dataSecurity",
defaultMessage: "Data security",
})}
</h4>
</Typography>
<ul className={styles.bullets}>
{security.map((text, i) => (
<li key={i} className={styles.bulletRow}>
<MaterialIcon icon="lock" size={20} color="Icon/Accent" />
<Typography variant="Body/Paragraph/mdRegular">
<p>{text}</p>
</Typography>
</li>
))}
</ul>
</div>
</div>
<TextLink
href={privacy[lang]}
color="Text/Interactive/Secondary"
typography="Link/md"
className={styles.learnMoreLink}
target="_blank"
onClick={() =>
trackLinkClick({
position: component,
name: "learn more about how we process your data",
})
}
>
{intl.formatMessage({
id: "profilingConsent.learnMoreAboutProcessing",
defaultMessage: "Learn more about how we process your data",
})}
<MaterialIcon
icon="open_in_new"
size={20}
color="Icon/Interactive/Secondary"
/>
</TextLink>
</AccordionItem>
<AccordionItem
title={intl.formatMessage({
id: "profilingConsent.readMoreAboutPersonalization",
@@ -246,7 +33,7 @@ export default function ProfilingConsentAccordion({
className={styles.accordionItem}
>
<Typography variant="Body/Paragraph/mdRegular">
<p>{getLegalText(intl, lang)}</p>
<p>{getLegalText(intl, lang, component)}</p>
</Typography>
</AccordionItem>
</Accordion>

View File

@@ -3,10 +3,18 @@ import { TextLink } from "@scandic-hotels/design-system/TextLink"
import { partners } from "@/constants/webHrefs"
import { trackLinkClick } from "@/utils/tracking/profilingConsent"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { IntlShape } from "react-intl"
export function getLegalText(intl: IntlShape, lang: Lang) {
import type { ProfilingConsentAccordionProps } from "."
export function getLegalText(
intl: IntlShape,
lang: Lang,
component: ProfilingConsentAccordionProps["component"]
) {
const partnerLink = partners[lang]
const privacyPolicyLink = privacy[lang]
@@ -28,6 +36,12 @@ export function getLegalText(intl: IntlShape, lang: Lang) {
{
partnerLink: (linkText) => (
<TextLink
onClick={() =>
trackLinkClick({
position: component,
name: linkText[0],
})
}
href={partnerLink}
color="Text/Interactive/Secondary"
typography="Link/md"
@@ -39,6 +53,12 @@ export function getLegalText(intl: IntlShape, lang: Lang) {
),
privacyPolicyLink: (linkText) => (
<TextLink
onClick={() =>
trackLinkClick({
position: component,
name: linkText[0],
})
}
href={privacyPolicyLink}
color="Text/Interactive/Secondary"
typography="Link/md"

View File

@@ -1,79 +1,7 @@
.divider {
margin: var(--Space-x1) 0;
}
.accordion {
width: 100%;
}
.list {
display: grid;
gap: var(--Space-x15);
}
.row {
display: grid;
grid-template-columns: 40px 1fr;
gap: var(--Space-x2);
align-items: start;
border: 0.696px solid var(--Border-Divider-Subtle);
border-radius: var(--Corner-radius-md);
background: var(--Surface-Primary-OnSurface-Default);
padding: var(--Space-x1);
}
.accordionItem:first-child {
border-top: 1px solid var(--Border-Default);
}
.rowIcon {
display: flex;
align-items: center;
justify-content: center;
place-self: center;
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--Surface-Primary-Default);
}
.rowText {
display: grid;
gap: 2px;
}
.columns {
display: grid;
gap: var(--Space-x3);
margin-bottom: var(--Space-x3);
}
.column {
display: grid;
gap: var(--Space-x1);
height: fit-content;
}
.bullets {
display: grid;
gap: var(--Space-x1);
}
.bulletRow {
display: grid;
grid-template-columns: 20px 1fr;
gap: var(--Space-x1);
align-items: start;
}
.learnMoreLink {
display: flex;
gap: var(--Space-x05);
justify-content: left;
}
@media (min-width: 768px) {
.columns {
grid-template-columns: 1fr 1fr;
}
}

View File

@@ -32,7 +32,7 @@
box-shadow: var(--modal-box-shadow);
width: 100%;
max-width: 100%;
border-radius: var(--Corner-radius-xLarge) var(--Corner-radius-xLarge) 0 0;
border-radius: var(--Corner-radius-xl) var(--Corner-radius-xl) 0 0;
}
.dialog {
@@ -90,8 +90,8 @@
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-bottom-right-radius: var(--Corner-radius-xLarge);
border-bottom-left-radius: var(--Corner-radius-xLarge);
border-bottom-right-radius: var(--Corner-radius-xl);
border-bottom-left-radius: var(--Corner-radius-xl);
}
.container {
@@ -119,7 +119,7 @@
.modal {
width: 95%;
max-width: 95%;
border-radius: var(--Corner-radius-xLarge);
border-radius: var(--Corner-radius-xl);
}
.actions {