Merged in feat/LOY-315-Membership-Status-Card (pull request #2712)
Feat(LOY-315): Membership Overview Card * fix(LOY-315): new divider variants * feat(LOY-315): Add MembershipOverviewCard * refactor(LOY-315): abstract sasbooststatus * fix(LOY-315): correct space vars * fix(LOY-315): date formatting fixes Approved-by: Erik Tiekstra
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
|
import { getLang } from "@/i18n/serverContext"
|
||||||
|
|
||||||
|
import styles from "./membershipOverviewCard.module.css"
|
||||||
|
|
||||||
|
import type { EurobonusMembership } from "@scandic-hotels/trpc/types/user"
|
||||||
|
import type { IntlShape } from "react-intl"
|
||||||
|
|
||||||
|
interface SasBoostStatusProps {
|
||||||
|
sasMembership: EurobonusMembership
|
||||||
|
intl: IntlShape
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function SasBoostStatus({
|
||||||
|
sasMembership,
|
||||||
|
intl,
|
||||||
|
}: SasBoostStatusProps) {
|
||||||
|
const lang = await getLang()
|
||||||
|
|
||||||
|
if (!sasMembership.boostedTierExpires) return null
|
||||||
|
|
||||||
|
const sasBoostExpiryText = intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "Boosted by SAS until {date}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: dt(sasMembership.boostedTierExpires)
|
||||||
|
.locale(lang)
|
||||||
|
.format("D MMM YYYY"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Divider variant="vertical" color="Border/Divider/Accent" />
|
||||||
|
<Typography variant="Label/xsRegular">
|
||||||
|
<span className={styles.sasBoostText}>{sasBoostExpiryText}</span>
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import { MembershipLevelEnum } from "@scandic-hotels/common/constants/membershipLevels"
|
||||||
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
import { getEurobonusMembership } from "@scandic-hotels/trpc/routers/user/helpers"
|
||||||
|
|
||||||
|
import { membershipLevels } from "@/constants/membershipLevels"
|
||||||
|
|
||||||
|
import MembershipLevelIcon from "@/components/Levels/Icon"
|
||||||
|
import { getIntl } from "@/i18n"
|
||||||
|
|
||||||
|
import SasBoostStatus from "./SasBoostStatus"
|
||||||
|
|
||||||
|
import styles from "./membershipOverviewCard.module.css"
|
||||||
|
|
||||||
|
import type { User } from "@scandic-hotels/trpc/types/user"
|
||||||
|
|
||||||
|
interface MembershipOverviewCardProps {
|
||||||
|
user: User
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function MembershipOverviewCard({
|
||||||
|
user,
|
||||||
|
}: MembershipOverviewCardProps) {
|
||||||
|
const intl = await getIntl()
|
||||||
|
|
||||||
|
if (!user.membership?.membershipLevel) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const pointsToSpendText =
|
||||||
|
typeof user.membership.currentPoints === "number"
|
||||||
|
? intl.formatNumber(user.membership.currentPoints)
|
||||||
|
: intl.formatMessage({ defaultMessage: "N/A" })
|
||||||
|
|
||||||
|
const sasMembership = user.loyalty
|
||||||
|
? getEurobonusMembership(user.loyalty)
|
||||||
|
: null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={styles.card} aria-labelledby="membership-level">
|
||||||
|
<header className={styles.membershipHeader}>
|
||||||
|
{sasMembership && (
|
||||||
|
<MaterialIcon icon="travel" size={20} color="Icon/Accent" />
|
||||||
|
)}
|
||||||
|
<Typography variant="Title/Overline/sm">
|
||||||
|
<h2 className={styles.levelText} id="membership-level">
|
||||||
|
{intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "LEVEL {level}",
|
||||||
|
},
|
||||||
|
{ level: membershipLevels[user.membership.membershipLevel] }
|
||||||
|
)}
|
||||||
|
</h2>
|
||||||
|
</Typography>
|
||||||
|
{sasMembership && (
|
||||||
|
<SasBoostStatus sasMembership={sasMembership} intl={intl} />
|
||||||
|
)}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<MembershipLevelIcon
|
||||||
|
level={MembershipLevelEnum[user.membership.membershipLevel]}
|
||||||
|
height="44"
|
||||||
|
width="268"
|
||||||
|
rows={1}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Divider
|
||||||
|
className={styles.divider}
|
||||||
|
color="Border/Divider/Brand/OnPrimary 3/Default"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Typography variant="Title/Overline/sm">
|
||||||
|
<h3 className={styles.pointsLabel}>
|
||||||
|
{intl.formatMessage({
|
||||||
|
defaultMessage: "POINTS TO SPEND",
|
||||||
|
})}
|
||||||
|
</h3>
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="Title/lg">
|
||||||
|
<p className={styles.pointsValue}>{pointsToSpendText}</p>
|
||||||
|
</Typography>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
.card {
|
||||||
|
background-color: var(--Surface-Brand-Primary-3-Default);
|
||||||
|
border-radius: var(--Corner-radius-lg);
|
||||||
|
padding: var(--Space-x3) var(--Space-x2);
|
||||||
|
position: relative;
|
||||||
|
min-height: 200px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.membershipHeader {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--Space-x1);
|
||||||
|
margin-bottom: var(--Space-x05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.levelText,
|
||||||
|
.sasBoostText,
|
||||||
|
.pointsLabel {
|
||||||
|
color: var(--Text-Brand-OnPrimary-3-Heading);
|
||||||
|
}
|
||||||
|
|
||||||
|
.levelText {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
margin: var(--Space-x4) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointsValue {
|
||||||
|
color: var(--Text-Brand-OnPrimary-3-Accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1367px) {
|
||||||
|
.card {
|
||||||
|
padding: var(--Space-x3) var(--Space-x4);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ import { Divider } from "@scandic-hotels/design-system/Divider"
|
|||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
|
|
||||||
import { env } from "@/env/server"
|
import { env } from "@/env/server"
|
||||||
import { getProfile } from "@/lib/trpc/memoizedRequests"
|
import { getProfileWithExtendedPartnerData } from "@/lib/trpc/memoizedRequests"
|
||||||
|
|
||||||
import { TeamMemberCardTrigger } from "@/components/DigitalTeamMemberCard/Trigger"
|
import { TeamMemberCardTrigger } from "@/components/DigitalTeamMemberCard/Trigger"
|
||||||
import DigitalTeamMemberCard from "@/components/MyPages/DigitalTeamMemberCard"
|
import DigitalTeamMemberCard from "@/components/MyPages/DigitalTeamMemberCard"
|
||||||
@@ -15,6 +15,7 @@ import { getIntl } from "@/i18n"
|
|||||||
import Hero from "./Friend/Hero"
|
import Hero from "./Friend/Hero"
|
||||||
import MembershipNumber from "./Friend/MembershipNumber"
|
import MembershipNumber from "./Friend/MembershipNumber"
|
||||||
import Friend from "./Friend"
|
import Friend from "./Friend"
|
||||||
|
import MembershipOverviewCard from "./MembershipOverviewCard"
|
||||||
import Stats from "./Stats"
|
import Stats from "./Stats"
|
||||||
import UserBaseInfo from "./UserBaseInfo"
|
import UserBaseInfo from "./UserBaseInfo"
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ export default async function Overview({
|
|||||||
title,
|
title,
|
||||||
}: AccountPageComponentProps) {
|
}: AccountPageComponentProps) {
|
||||||
const intl = await getIntl()
|
const intl = await getIntl()
|
||||||
const user = await getProfile()
|
const user = await getProfileWithExtendedPartnerData()
|
||||||
if (!user || "error" in user) {
|
if (!user || "error" in user) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -58,8 +59,17 @@ export default async function Overview({
|
|||||||
</>
|
</>
|
||||||
</TeamMemberCardTrigger>
|
</TeamMemberCardTrigger>
|
||||||
</DigitalTeamMemberCard>
|
</DigitalTeamMemberCard>
|
||||||
{env.ENABLE_NEW_OVERVIEW_SECTION ? <UserBaseInfo user={user} /> : null}
|
{env.ENABLE_NEW_OVERVIEW_SECTION ? (
|
||||||
{/*TODO: Replace Hero Section Cards with New ones. */}
|
<>
|
||||||
|
<UserBaseInfo user={user} />
|
||||||
|
<div className={styles.membershipCardsContainer}>
|
||||||
|
<MembershipOverviewCard user={user} />
|
||||||
|
{/* LevelProgressCard will be added here in the next iteration */}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{/*TODO: Replace hero section with new section above. */}
|
||||||
<Hero color="red">
|
<Hero color="red">
|
||||||
<Friend membership={user.membership} name={user.name}>
|
<Friend membership={user.membership} name={user.name}>
|
||||||
<MembershipNumber color="burgundy" membership={user.membership} />
|
<MembershipNumber color="burgundy" membership={user.membership} />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.divider {
|
.divider {
|
||||||
margin-top: var(--Spacing-x2);
|
margin-top: var(--Space-x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.teamMemberCardButton {
|
.teamMemberCardButton {
|
||||||
@@ -12,17 +12,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 767px) {
|
.membershipCardsContainer {
|
||||||
.container {
|
display: grid;
|
||||||
/* Full-width override styling */
|
gap: var(--Space-x2);
|
||||||
left: 50%;
|
|
||||||
margin-left: -50vw;
|
|
||||||
margin-right: -50vw;
|
|
||||||
padding: 0 var(--Spacing-x2);
|
|
||||||
position: relative;
|
|
||||||
right: 50%;
|
|
||||||
width: 100dvw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
@@ -30,3 +22,9 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1367px) {
|
||||||
|
.membershipCardsContainer {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,10 @@
|
|||||||
background-color: var(--UI-Opacity-White-100);
|
background-color: var(--UI-Opacity-White-100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Border-Divider-Accent {
|
||||||
|
background-color: var(--Border-Divider-Accent);
|
||||||
|
}
|
||||||
|
|
||||||
.Border-Divider-Subtle {
|
.Border-Divider-Subtle {
|
||||||
background-color: var(--Border-Divider-Subtle);
|
background-color: var(--Border-Divider-Subtle);
|
||||||
}
|
}
|
||||||
@@ -37,6 +41,10 @@
|
|||||||
background-color: var(--Border-Divider-Default);
|
background-color: var(--Border-Divider-Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Border-Divider-Brand-OnPrimary-3-Default {
|
||||||
|
background: var(--Border-Divider-Brand-OnPrimary-3-Default);
|
||||||
|
}
|
||||||
|
|
||||||
.Surface-Brand-Primary-1-OnSurface-Accent-Secondary {
|
.Surface-Brand-Primary-1-OnSurface-Accent-Secondary {
|
||||||
background-color: var(--Surface-Brand-Primary-1-OnSurface-Accent-Secondary);
|
background-color: var(--Surface-Brand-Primary-1-OnSurface-Accent-Secondary);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ export const dividerVariants = cva(styles.divider, {
|
|||||||
pale: styles.pale,
|
pale: styles.pale,
|
||||||
peach: styles.peach,
|
peach: styles.peach,
|
||||||
white: styles.white,
|
white: styles.white,
|
||||||
|
'Border/Divider/Accent': styles['Border-Divider-Accent'],
|
||||||
'Border/Divider/Default': styles['Border-Divider-Default'],
|
'Border/Divider/Default': styles['Border-Divider-Default'],
|
||||||
|
'Border/Divider/Brand/OnPrimary 3/Default':
|
||||||
|
styles['Border-Divider-Brand-OnPrimary-3-Default'],
|
||||||
'Border/Divider/Subtle': styles['Border-Divider-Subtle'],
|
'Border/Divider/Subtle': styles['Border-Divider-Subtle'],
|
||||||
'Surface/Brand/Primary 1/OnSurface/Accent Secondary':
|
'Surface/Brand/Primary 1/OnSurface/Accent Secondary':
|
||||||
styles['Surface-Brand-Primary-1-OnSurface-Accent-Secondary'],
|
styles['Surface-Brand-Primary-1-OnSurface-Accent-Secondary'],
|
||||||
|
|||||||
Reference in New Issue
Block a user