Merged in feat/LOY-285-SAS-marketing-banner-my-pages (pull request #2544)

feat(LOY-285): SAS Link Account Banner for My Pages (Part 1)

* feat(LOY-285): SAS Link Account Banner for My Pages

* fix(LOY-285): )use new space variable

* fix(LOY-285): add alt to images


Approved-by: Matilda Landström
This commit is contained in:
Chuma Mcphoy (We Ahead)
2025-07-11 08:37:25 +00:00
parent ab233fb1c0
commit 960787f82c
6 changed files with 252 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
import { Typography } from "@scandic-hotels/design-system/Typography"
import { getEurobonusMembership } from "@scandic-hotels/trpc/routers/user/helpers"
import { getProfileWithExtendedPartnerData } from "@/lib/trpc/memoizedRequests"
import ButtonLink from "@/components/ButtonLink"
import Image from "@/components/Image"
import { getIntl } from "@/i18n"
import desktopBackground from "@/public/_static/img/sas/sas-scandic-link-account-banner-desktop.png"
import mobileBackground from "@/public/_static/img/sas/sas-scandic-link-account-banner-mobile.png"
import styles from "./linkAccountBanner.module.css"
import type { DynamicContentProps } from "@/types/components/blocks/dynamicContent"
export default async function SASLinkAccountBanner(
props: DynamicContentProps["dynamic_content"]
) {
const intl = await getIntl()
const user = await getProfileWithExtendedPartnerData()
if (!user || "error" in user || !user.loyalty) {
return null
}
const sasMembership = getEurobonusMembership(user.loyalty)
if (sasMembership) {
return null
}
function match() {
return (
<span key="match" className={styles.highlight}>
{intl.formatMessage({
defaultMessage: "MATCH",
})}
</span>
)
}
const headingText = intl.formatMessage(
{
defaultMessage: "A <match></match> MADE IN HEAVEN",
},
{
match,
}
)
const buttonText =
props.link?.text ||
intl.formatMessage({
defaultMessage: "Read more and link accounts",
})
function scandicFriends() {
return (
<span key="scandic-friends" className={styles.brandName}>
{intl.formatMessage({
defaultMessage: "Scandic Friends",
})}
</span>
)
}
function sasEuroBonus() {
return (
<span key="sas-eurobonus" className={styles.brandName}>
{intl.formatMessage({
defaultMessage: "SAS EuroBonus",
})}
</span>
)
}
const descriptionText = intl.formatMessage(
{
defaultMessage:
"Link your <scandicFriends></scandicFriends> and <sasEuroBonus></sasEuroBonus> accounts to earn, use and exchange points between memberships",
},
{
scandicFriends,
sasEuroBonus,
}
)
return (
<div className={styles.container}>
<div className={styles.backgroundImage}>
<Image
src={mobileBackground}
alt="SAS Scandic Link Account Banner Mobile Background"
fill
className={styles.mobileImage}
priority
/>
<Image
src={desktopBackground}
alt="SAS Scandic Link Account Banner Desktop Background"
fill
className={styles.desktopImage}
priority
/>
<div className={styles.overlay} />
</div>
<div className={styles.content}>
<div className={styles.headingContainer}>
<Typography variant="Title/md">
<h2 className={styles.heading}>{headingText}</h2>
</Typography>
</div>
<div className={styles.descriptionContainer}>
<Typography variant="Body/Lead text">
<p>{descriptionText}</p>
</Typography>
</div>
{props.link?.href ? (
<div className={styles.buttonContainer}>
<ButtonLink
href={props.link.href}
variant="Primary"
color="Inverted"
size="Medium"
>
{buttonText}
</ButtonLink>
</div>
) : null}
</div>
</div>
)
}

View File

@@ -0,0 +1,114 @@
.container {
position: relative;
overflow: hidden;
border-radius: var(--Corner-radius-lg);
background: linear-gradient(
to right,
var(--Scandic-Blue-60),
var(--Scandic-Blue-80)
);
}
.backgroundImage {
position: absolute;
inset: 0;
}
.mobileImage {
object-fit: cover;
display: block;
}
.desktopImage {
object-fit: cover;
display: none;
}
.overlay {
position: absolute;
inset: 0;
background: linear-gradient(
180deg,
rgba(0, 0, 0, 0) 23.33%,
rgba(0, 0, 0, 0.25) 61.67%,
rgba(0, 0, 0, 0.52) 100%
);
}
.content {
position: relative;
z-index: 10;
display: grid;
grid-template-areas:
"heading"
"description"
"button";
gap: var(--Space-x2);
min-height: 200px;
color: var(--Text-Inverted);
padding: var(--Space-x5) var(--Space-x3);
}
.headingContainer {
grid-area: heading;
}
.descriptionContainer {
grid-area: description;
}
.buttonContainer {
grid-area: button;
justify-self: start;
}
.brandName {
font-weight: 600;
}
.highlight {
color: var(--Scandic-Brand-Burgundy);
}
@media (min-width: 768px) {
.container {
background: linear-gradient(
to right,
var(--Scandic-Yellow-10),
var(--Scandic-Peach-20)
);
}
.mobileImage {
display: none;
}
.desktopImage {
display: block;
}
.overlay {
background: linear-gradient(
180deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.18) 50%,
rgba(0, 0, 0, 0.38) 100%
);
}
.content {
grid-template-areas:
"heading button"
"description button";
grid-template-columns: 2fr 1fr;
gap: var(--Space-x2) var(--Space-x4);
padding: var(--Space-x4) var(--Space-x4) var(--Space-x5);
}
.headingContainer {
align-self: end;
}
.descriptionContainer {
align-self: start;
}
.buttonContainer {
justify-self: center;
align-self: center;
}
}

View File

@@ -11,6 +11,7 @@ import ExpiringPoints from "@/components/Blocks/DynamicContent/Points/ExpiringPo
import PointsOverview from "@/components/Blocks/DynamicContent/Points/Overview"
import CurrentRewardsBlock from "@/components/Blocks/DynamicContent/Rewards/CurrentRewards"
import NextLevelRewardsBlock from "@/components/Blocks/DynamicContent/Rewards/NextLevel"
import SASLinkAccountBanner from "@/components/Blocks/DynamicContent/SAS/LinkAccountBanner"
import SASLinkedAccount from "@/components/Blocks/DynamicContent/SAS/LinkedAccounts"
import SASTransferPoints from "@/components/Blocks/DynamicContent/SAS/TransferPoints"
import SASTierComparisonBlock from "@/components/Blocks/DynamicContent/SASTierComparison"
@@ -63,6 +64,8 @@ function DynamicContentBlocks(props: DynamicContentProps) {
return <UpcomingStays {...dynamic_content} />
case DynamicContentEnum.Blocks.components.sas_linked_account:
return <SASLinkedAccount {...dynamic_content} />
case DynamicContentEnum.Blocks.components.sas_link_account_banner:
return <SASLinkAccountBanner {...dynamic_content} />
case DynamicContentEnum.Blocks.components.sas_transfer_points:
return <SASTransferPoints {...dynamic_content} />
case DynamicContentEnum.Blocks.components.sas_tier_comparison:

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

View File

@@ -21,6 +21,7 @@ export namespace DynamicContentEnum {
soonest_stays: "soonest_stays",
upcoming_stays: "upcoming_stays",
sas_linked_account: "sas_linked_account",
sas_link_account_banner: "sas_link_account_banner",
sas_transfer_points: "sas_transfer_points",
sas_tier_comparison: "sas_tier_comparison",
} as const