Merged in feature/sas-mypages (pull request #1302)

Feature/sas mypages

* feat: Add SAS partner page under my pages
* fix: feature toggle SAS Partner page in my pages
* add translations for SAS account page
* use 'flex-start' instead of 'start'
* fix: flatten css
* fix: don't use <SectionContainer /> on linkedAccounts page
This commit is contained in:
Joakim Jäderberg
2025-02-11 12:55:00 +00:00
parent 98e3afe9db
commit 3d11cfb50a
37 changed files with 875 additions and 20 deletions

View File

@@ -0,0 +1,207 @@
import { cva, type VariantProps } from "class-variance-authority"
import Image from "next/image"
import RocketLaunch from "@/components/Icons/RocketLaunch"
import SkeletonShimmer from "@/components/SkeletonShimmer"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import { getIntl } from "@/i18n"
import styles from "./tierLevelCard.module.css"
import type { ComponentProps, ReactNode } from "react"
type BoostState = "boostedInOtherSystem" | "boostedInThisSystem" | "notBoosted"
type BaseProps = {
points: number
tier: string
boostState: BoostState
}
type BoostedInOther = BaseProps & {
boostState: "boostedInOtherSystem"
boostedTier: string
boostExpiration: Date
}
type BoostedInThis = BaseProps & {
boostState: "boostedInThisSystem"
}
type NotBoosted = BaseProps & {
boostState: "notBoosted"
}
const variants = cva(styles.tierlevelcard, {
variants: {
bonusSystem: {
scandic: styles.scandic,
sas: styles.sas,
},
},
})
type Props = VariantProps<typeof variants> &
(BoostedInOther | BoostedInThis | NotBoosted)
export async function TierLevelCard({
points,
tier,
bonusSystem,
...boosted
}: Props) {
const intl = await getIntl()
const className = variants({ bonusSystem })
return (
<article className={className}>
{boosted.boostState === "boostedInOtherSystem" && (
<section className={styles.boostedInfo}>
<div className={styles.boostedTier}>
<Caption
uppercase
type="bold"
color={bonusSystemSpecifics[bonusSystem!].color}
>
{boosted.boostedTier}
</Caption>
<Caption
type="bold"
color={bonusSystemSpecifics[bonusSystem!].color}
>
{intl.formatMessage({ id: "Level upgrade" })}
</Caption>
</div>
<Caption color={bonusSystemSpecifics[bonusSystem!].color}>
{intl.formatMessage(
{
id: "Upgrade expires {upgradeExpires, date, short}",
},
{ upgradeExpires: boosted.boostExpiration }
)}
</Caption>
</section>
)}
<section className={styles.baseInfo}>
<div className={styles.header}>
<div className={styles.tierInfo}>
<span>
<Caption
uppercase
type="bold"
color={bonusSystemSpecifics[bonusSystem!].color}
>
{tier}
</Caption>
</span>
<div className={styles.logoContainer}>
{bonusSystemSpecifics[bonusSystem!].logo}
</div>
</div>
{boosted.boostState === "boostedInThisSystem" && (
<Footnote className={styles.footnote}>
<RocketLaunch
color={bonusSystemSpecifics[bonusSystem!].rocketLaunchColor}
/>
<span>
{intl.formatMessage({
id: bonusSystemSpecifics[bonusSystem!].boostTextId,
})}
</span>
</Footnote>
)}
</div>
<Subtitle>
{intl.formatMessage(
{ id: "{points, number} Bonus points" },
{ points }
)}
</Subtitle>
</section>
</article>
)
}
export function TierLevelCardSkeleton({
bonusSystem,
}: {
bonusSystem?: NonNullable<Props["bonusSystem"]>
}) {
const className = variants({ bonusSystem })
return (
<article className={className}>
<section className={styles.baseInfo}>
<div className={styles.header}>
<div className={styles.tierInfo}>
<span>
<SkeletonShimmer width={"50px"} height={"16px"} />
</span>
{bonusSystem && (
<div className={styles.eurobonusLogo}>
{bonusSystemSpecifics[bonusSystem!].logo}
</div>
)}
{!bonusSystem && <SkeletonShimmer width={"74px"} height={"16px"} />}
</div>
</div>
<Subtitle>
<SkeletonShimmer width={"240px"} height={"26px"} />
</Subtitle>
</section>
</article>
)
}
type BonusSystemSpecifics = {
boostTextId: string
logo: ReactNode
rocketLaunchColor: ComponentProps<typeof RocketLaunch>["color"]
color: ComponentProps<typeof Caption>["color"]
}
type BonusSystemMapping = {
[bonusSystem in NonNullable<
VariantProps<typeof variants>["bonusSystem"]
>]: BonusSystemSpecifics
}
const bonusSystemSpecifics: BonusSystemMapping = {
scandic: {
boostTextId: "Your Friends level has upgraded your Eurobonus level",
rocketLaunchColor: "red",
color: "burgundy",
logo: (
<Image
alt="Scandic logo"
height={16}
src="/_static/img/scandic-logotype.svg"
width={74}
/>
),
},
sas: {
boostTextId: "Your Eurobonus level has upgraded your friends level",
rocketLaunchColor: "blue",
color: "uiTextActive",
logo: (
<>
<Image
alt="SAS logo"
height={16}
src="/_static/img/sas/sas-logotype.svg"
width={44}
/>
<Caption uppercase type="bold">
Eurobonus
</Caption>
</>
),
},
}

View File

@@ -0,0 +1,93 @@
.tierlevelcard {
display: flex;
flex-direction: column;
justify-content: space-between;
border-radius: var(--Corner-radius-Medium);
background: white;
box-shadow: 0px 0px 8px 3px #0000001a;
overflow: hidden;
width: 100%;
min-height: 176px;
@media screen and (min-width: 768px) {
max-width: 335px;
}
&.scandic {
background: white;
color: var(--Main-Brand-Burgundy);
.boostedInfo {
background: linear-gradient(86.64deg, #faf6f2 0%, #f4d5c8 100.91%);
border-radius: var(--Corner-radius-Medium);
}
}
&.sas {
background: #f0f4ff;
color: var(--Main-Brand-DarkBlue);
.boostedInfo {
background: linear-gradient(90deg, #f0f4ff 0%, #bdcdff 100%);
border-radius: var(--Corner-radius-Medium);
}
}
}
.boostedInfo {
display: flex;
flex-direction: column;
gap: var(--Spacing-x-half);
box-shadow: 0px 0px 4px 2px #0000001a;
flex: 0;
padding: var(--Spacing-x2) var(--Spacing-x-one-and-half);
}
.boostedTier {
display: flex;
justify-content: space-between;
gap: var(--Spacing-x-one-and-half);
}
.baseInfo {
flex: 1;
display: flex;
flex-direction: column;
gap: var(--Spacing-x-one-and-half);
padding: var(--Spacing-x2) var(--Spacing-x-one-and-half);
justify-content: space-between;
}
.header {
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
}
.tierInfo {
display: flex;
justify-content: space-between;
text-transform: uppercase;
gap: var(--Spacing-x1);
}
.logoContainer {
display: flex;
justify-content: center;
align-items: center;
gap: var(--Spacing-x1);
}
.footnote {
display: flex;
align-items: center;
justify-content: flex-start;
gap: var(--Spacing-x1);
}