fix: cleanup profile pages in renaming to follow naming convention
cleanup profile page html to be valid replace old temp design system components with new ones divider is now correctly an hr element less section elements to be valid html
This commit is contained in:
@@ -14,15 +14,15 @@ export default async function MyPagesLayout({
|
||||
}>) {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<section className={styles.layout}>
|
||||
<div className={styles.layout}>
|
||||
{breadcrumbs}
|
||||
<section className={styles.content}>
|
||||
<div className={styles.content}>
|
||||
<Suspense fallback={<SidebarNavigationSkeleton />}>
|
||||
<Sidebar />
|
||||
</Suspense>
|
||||
{children}
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Surprises />
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import Profile from "@/components/MyPages/myprofile/profile/profile"
|
||||
import Profile from "@/components/MyPages/Profile"
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
.container {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x3);
|
||||
gap: var(--Space-x3);
|
||||
max-width: 510px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x1);
|
||||
gap: var(--Space-x1);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import ManagePreferencesButton from "@/components/Profile/ManagePreferencesButton"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./communication.module.css"
|
||||
|
||||
export default async function CommunicationSlot() {
|
||||
const intl = await getIntl()
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "My communication preferences",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Tell us what information and updates you'd like to receive, and how, by clicking the link below.",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<ManagePreferencesButton />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
.container {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
gap: var(--Space-x2);
|
||||
justify-items: flex-start;
|
||||
max-width: 510px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x1);
|
||||
gap: var(--Space-x1);
|
||||
}
|
||||
|
||||
.cardContainer {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x1);
|
||||
gap: var(--Space-x1);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.container {
|
||||
gap: var(--Spacing-x3);
|
||||
gap: var(--Space-x3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import AddCreditCardButton from "@/components/Profile/AddCreditCardButton"
|
||||
import CreditCardList from "@/components/Profile/CreditCardList"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./creditCards.module.css"
|
||||
|
||||
export default async function CreditCardSlot() {
|
||||
const intl = await getIntl()
|
||||
const creditCards = await serverClient().user.creditCards()
|
||||
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "My payment cards",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<CreditCardList initialData={creditCards} />
|
||||
<AddCreditCardButton />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { getMembershipCards } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./membershipcards.module.css"
|
||||
|
||||
export default async function MembershipCardSlot() {
|
||||
const intl = await getIntl()
|
||||
const membershipCards = await getMembershipCards()
|
||||
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "My membership cards",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
</div>
|
||||
{(membershipCards || []).map((card, idx) => (
|
||||
<div className={styles.card} key={idx}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h4 className={styles.subTitle}>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Name: {cardMembershipType}",
|
||||
},
|
||||
{
|
||||
cardMembershipType: card.membershipType,
|
||||
}
|
||||
)}
|
||||
</h4>
|
||||
</Typography>
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Current Points: {points, number}",
|
||||
},
|
||||
{ points: card.currentPoints }
|
||||
)}
|
||||
</span>
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Member Since: {value}",
|
||||
},
|
||||
{
|
||||
value: card.memberSince,
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Number: {membershipNumber}",
|
||||
},
|
||||
{
|
||||
membershipNumber: card.membershipNumber,
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Expiration Date: {expirationDate}",
|
||||
},
|
||||
{
|
||||
expirationDate: card.expirationDate?.split("T")[0],
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
<Link href="#" variant="icon">
|
||||
<MaterialIcon icon="add_circle" color="CurrentColor" />
|
||||
<Body color="burgundy" textTransform="underlined">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Add new card",
|
||||
})}
|
||||
</Body>
|
||||
</Link>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
.container {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x3);
|
||||
gap: var(--Space-x3);
|
||||
max-width: 510px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x1);
|
||||
gap: var(--Space-x1);
|
||||
}
|
||||
|
||||
.card {
|
||||
margin-top: 2rem;
|
||||
margin-top: var(--Space-x4);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-template-rows: repeat(3, auto);
|
||||
gap: 0.5rem;
|
||||
gap: var(--Space-x1);
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
182
apps/scandic-web/components/MyPages/Profile/index.tsx
Normal file
182
apps/scandic-web/components/MyPages/Profile/index.tsx
Normal file
@@ -0,0 +1,182 @@
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { countriesMap } from "@/constants/countries"
|
||||
import { Lang, languages } from "@/constants/languages"
|
||||
import { profileEdit } from "@/constants/routes/myPages"
|
||||
import { getProfile } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import ButtonLink from "@/components/ButtonLink"
|
||||
import CommunicationSlot from "@/components/MyPages/Profile/Communication"
|
||||
import CreditCardSlot from "@/components/MyPages/Profile/CreditCards"
|
||||
import Header from "@/components/Profile/Header"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { getLang } from "@/i18n/serverContext"
|
||||
import { isValidCountry } from "@/utils/countries"
|
||||
import { isValidLang } from "@/utils/languages"
|
||||
|
||||
import styles from "./profile.module.css"
|
||||
|
||||
export default async function Profile() {
|
||||
const user = await getProfile()
|
||||
if (!user || "error" in user) {
|
||||
return null
|
||||
}
|
||||
|
||||
const intl = await getIntl()
|
||||
const lang = getLang()
|
||||
|
||||
const addressParts = []
|
||||
if (user.address.streetAddress) {
|
||||
addressParts.push(user.address.streetAddress)
|
||||
}
|
||||
|
||||
if (user.address.city) {
|
||||
addressParts.push(user.address.city)
|
||||
}
|
||||
|
||||
const displayNames = {
|
||||
language: new Intl.DisplayNames([lang], { type: "language" }),
|
||||
region: new Intl.DisplayNames([lang], { type: "region" }),
|
||||
}
|
||||
|
||||
if (user.address.country) {
|
||||
const countryCode = isValidCountry(user.address.country)
|
||||
? countriesMap[user.address.country]
|
||||
: null
|
||||
const localizedCountry = countryCode
|
||||
? displayNames.region.of(countryCode)
|
||||
: user.address.country
|
||||
addressParts.push(localizedCountry)
|
||||
}
|
||||
|
||||
const addressOutput =
|
||||
addressParts.length > 0
|
||||
? addressParts.join(", ")
|
||||
: intl.formatMessage({
|
||||
defaultMessage: "N/A",
|
||||
})
|
||||
|
||||
const userLang = isValidLang(user.language) ? user.language : Lang.en
|
||||
const localizedLanguage = displayNames.language.of(userLang)
|
||||
const normalizedLanguage = localizedLanguage
|
||||
? localizedLanguage.charAt(0).toUpperCase() + localizedLanguage.slice(1)
|
||||
: languages[userLang]
|
||||
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<Header>
|
||||
<Typography variant="Title/xs">
|
||||
<h2 className={styles.title}>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Welcome",
|
||||
})}
|
||||
<br />
|
||||
<span data-hj-suppress className={styles.titleName}>
|
||||
{user.name}
|
||||
</span>
|
||||
</h2>
|
||||
</Typography>
|
||||
<ButtonLink
|
||||
size="Small"
|
||||
prefetch={false}
|
||||
href={profileEdit[lang]}
|
||||
typography="Body/Supporting text (caption)/smBold"
|
||||
>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Edit profile",
|
||||
})}
|
||||
</ButtonLink>
|
||||
</Header>
|
||||
<div className={styles.info}>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon
|
||||
icon="calendar_month"
|
||||
color="Icon/Interactive/Default"
|
||||
/>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Date of Birth",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{user.dateOfBirth}</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon icon="phone" color="Icon/Interactive/Default" />
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Phone number",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{user.phoneNumber}</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon icon="globe" color="Icon/Interactive/Default" />
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Language",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{normalizedLanguage}</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon icon="mail" color="Icon/Interactive/Default" />
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Email",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{user.email}</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon icon="location_on" color="Icon/Interactive/Default" />
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Address",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{addressOutput}</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon icon="lock" color="Icon/Interactive/Default" />
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Password",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
<p>**********</p>
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Divider color="burgundy" opacity={8} />
|
||||
<CreditCardSlot />
|
||||
{/* <MembershipCardSlot /> */}
|
||||
<CommunicationSlot />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,48 +1,59 @@
|
||||
.profile {
|
||||
display: flex;
|
||||
gap: var(--Spacing-x2);
|
||||
justify-content: space-between;
|
||||
}
|
||||
.info {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x-one-and-half) var(--Spacing-x7);
|
||||
width: 100%;
|
||||
justify-items: flex-start;
|
||||
}
|
||||
.item {
|
||||
align-items: center;
|
||||
display: grid;
|
||||
gap: var(--Spacing-x1);
|
||||
grid-template-columns: auto auto 1fr;
|
||||
justify-items: flex-end;
|
||||
width: 100%;
|
||||
}
|
||||
.content {
|
||||
display: grid;
|
||||
padding-bottom: var(--Spacing-x9);
|
||||
position: relative;
|
||||
}
|
||||
.container {
|
||||
background-color: var(--Main-Grey-White);
|
||||
border-radius: var(--Corner-radius-lg);
|
||||
display: grid;
|
||||
gap: var(--Spacing-x3);
|
||||
padding: var(--Spacing-x2) var(--Spacing-x2) var(--Spacing-x4);
|
||||
gap: var(--Space-x3);
|
||||
padding: var(--Space-x2) var(--Space-x2) var(--Space-x4);
|
||||
color: var(--Text-Default);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--Text-Accent-Primary);
|
||||
}
|
||||
|
||||
.titleName {
|
||||
color: var(--Text-Interactive-Default);
|
||||
}
|
||||
|
||||
.info {
|
||||
display: grid;
|
||||
gap: var(--Space-x15) var(--Space-x7);
|
||||
width: 100%;
|
||||
justify-items: flex-start;
|
||||
}
|
||||
|
||||
.item {
|
||||
align-items: center;
|
||||
display: grid;
|
||||
gap: var(--Space-x1);
|
||||
grid-template-columns: auto auto 1fr;
|
||||
justify-items: flex-end;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
padding-bottom: var(--Space-x8);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.info {
|
||||
grid-template-columns: repeat(3, auto);
|
||||
}
|
||||
|
||||
.item {
|
||||
justify-items: flex-start;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: var(--Spacing-x3) var(--Spacing-x3) var(--Spacing-x4);
|
||||
padding: var(--Space-x3) var(--Space-x3) var(--Space-x4);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.content {
|
||||
gap: var(--Spacing-x5);
|
||||
gap: var(--Space-x5);
|
||||
grid-template-columns: max(340px) 1fr;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Fragment } from "react"
|
||||
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import SkeletonShimmer from "@/components/SkeletonShimmer"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
|
||||
import styles from "./sidebar.module.css"
|
||||
|
||||
@@ -12,9 +13,9 @@ export default function SidebarNavigationSkeleton() {
|
||||
return (
|
||||
<aside className={styles.sidebar}>
|
||||
<nav className={styles.nav}>
|
||||
<Subtitle type="two" color="baseTextHighContrast">
|
||||
<SkeletonShimmer width={"10ch"} />
|
||||
</Subtitle>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<SkeletonShimmer width="10ch" />
|
||||
</Typography>
|
||||
<Divider color="beige" />
|
||||
<ul className={styles.list}>
|
||||
{skeletonWidths.map((width, index) => (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { logout } from "@/constants/routes/handleAuth"
|
||||
import { getProfileSafely } from "@/lib/trpc/memoizedRequests"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
@@ -5,7 +7,6 @@ import { serverClient } from "@/lib/trpc/server"
|
||||
import { SASLevelUpgradeCheck } from "@/components/MyPages/SASLevelUpgradeCheck"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { getLang } from "@/i18n/serverContext"
|
||||
import { getEurobonusMembership } from "@/utils/user"
|
||||
@@ -22,11 +23,13 @@ export default async function SidebarMyPages() {
|
||||
return (
|
||||
<aside className={styles.sidebar}>
|
||||
<nav className={styles.nav}>
|
||||
<Subtitle type="two" color="baseTextHighContrast">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "My pages",
|
||||
})}
|
||||
</Subtitle>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h2 className={styles.title}>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "My pages",
|
||||
})}
|
||||
</h2>
|
||||
</Typography>
|
||||
|
||||
<PrimaryLinks />
|
||||
<SecondaryLinks />
|
||||
|
||||
@@ -4,7 +4,15 @@
|
||||
|
||||
.nav {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
gap: var(--Space-x2);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--Text-Interactive-Default);
|
||||
}
|
||||
|
||||
.titleSkeleton {
|
||||
color: var(--Base-Text-High-contrast);
|
||||
}
|
||||
|
||||
.list {
|
||||
@@ -15,6 +23,6 @@
|
||||
.sidebar {
|
||||
align-self: flex-start;
|
||||
display: block;
|
||||
padding-top: var(--Spacing-x1);
|
||||
padding-top: var(--Space-x1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import ManagePreferencesButton from "@/components/Profile/ManagePreferencesButton"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./communication.module.css"
|
||||
|
||||
export default async function CommunicationSlot() {
|
||||
const intl = await getIntl()
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<article className={styles.content}>
|
||||
<Subtitle type="two" color="black">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "My communication preferences",
|
||||
})}
|
||||
</Subtitle>
|
||||
<Body color="black">
|
||||
{intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Tell us what information and updates you'd like to receive, and how, by clicking the link below.",
|
||||
})}
|
||||
</Body>
|
||||
</article>
|
||||
<ManagePreferencesButton />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import AddCreditCardButton from "@/components/Profile/AddCreditCardButton"
|
||||
import CreditCardList from "@/components/Profile/CreditCardList"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./creditCards.module.css"
|
||||
|
||||
export default async function CreditCardSlot() {
|
||||
const intl = await getIntl()
|
||||
const creditCards = await serverClient().user.creditCards()
|
||||
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<article className={styles.content}>
|
||||
<Subtitle type="two" color="black">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "My payment cards",
|
||||
})}
|
||||
</Subtitle>
|
||||
<Body color="black">
|
||||
{intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.",
|
||||
})}
|
||||
</Body>
|
||||
</article>
|
||||
<CreditCardList initialData={creditCards} />
|
||||
<AddCreditCardButton />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
|
||||
import { getMembershipCards } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./membershipcards.module.css"
|
||||
|
||||
export default async function MembershipCardSlot() {
|
||||
const intl = await getIntl()
|
||||
const membershipCards = await getMembershipCards()
|
||||
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<article className={styles.content}>
|
||||
<Subtitle color="black">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "My membership cards",
|
||||
})}
|
||||
</Subtitle>
|
||||
</article>
|
||||
{membershipCards &&
|
||||
membershipCards.length > 0 &&
|
||||
membershipCards.map((card, idx) => (
|
||||
<div className={styles.card} key={idx}>
|
||||
<Subtitle className={styles.subTitle}>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Name: {cardMembershipType}",
|
||||
},
|
||||
{
|
||||
cardMembershipType: card.membershipType,
|
||||
}
|
||||
)}
|
||||
</Subtitle>
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Current Points: {points, number}",
|
||||
},
|
||||
{ points: card.currentPoints }
|
||||
)}
|
||||
</span>
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Member Since: {value}",
|
||||
},
|
||||
{
|
||||
value: card.memberSince,
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Number: {membershipNumber}",
|
||||
},
|
||||
{
|
||||
membershipNumber: card.membershipNumber,
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Expiration Date: {expirationDate}",
|
||||
},
|
||||
{
|
||||
expirationDate: card.expirationDate?.split("T")[0],
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
<Link href="#" variant="icon">
|
||||
<MaterialIcon icon="add_circle" color="CurrentColor" />
|
||||
<Body color="burgundy" textTransform="underlined">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Add new card",
|
||||
})}
|
||||
</Body>
|
||||
</Link>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
|
||||
import { countriesMap } from "@/constants/countries"
|
||||
import { Lang, languages } from "@/constants/languages"
|
||||
import { profileEdit } from "@/constants/routes/myPages"
|
||||
import { getProfile } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import CommunicationSlot from "@/components/MyPages/myprofile/communication/communication"
|
||||
import CreditCardSlot from "@/components/MyPages/myprofile/creditCards/creditCards"
|
||||
import Header from "@/components/Profile/Header"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { getLang } from "@/i18n/serverContext"
|
||||
import { isValidCountry } from "@/utils/countries"
|
||||
import { isValidLang } from "@/utils/languages"
|
||||
|
||||
import styles from "./profile.module.css"
|
||||
|
||||
export default async function Profile() {
|
||||
const intl = await getIntl()
|
||||
const lang = getLang()
|
||||
const user = await getProfile()
|
||||
if (!user || "error" in user) {
|
||||
return null
|
||||
}
|
||||
|
||||
const addressParts = []
|
||||
if (user.address.streetAddress) {
|
||||
addressParts.push(user.address.streetAddress)
|
||||
}
|
||||
|
||||
if (user.address.city) {
|
||||
addressParts.push(user.address.city)
|
||||
}
|
||||
|
||||
const displayNames = {
|
||||
language: new Intl.DisplayNames([lang], { type: "language" }),
|
||||
region: new Intl.DisplayNames([lang], { type: "region" }),
|
||||
}
|
||||
|
||||
if (user.address.country) {
|
||||
const countryCode = isValidCountry(user.address.country)
|
||||
? countriesMap[user.address.country]
|
||||
: null
|
||||
const localizedCountry = countryCode
|
||||
? displayNames.region.of(countryCode)
|
||||
: user.address.country
|
||||
addressParts.push(localizedCountry)
|
||||
}
|
||||
|
||||
const addressOutput =
|
||||
addressParts.length > 0
|
||||
? addressParts.join(", ")
|
||||
: intl.formatMessage({
|
||||
defaultMessage: "N/A",
|
||||
})
|
||||
|
||||
const userLang = isValidLang(user.language) ? user.language : Lang.en
|
||||
const localizedLanguage = displayNames.language.of(userLang)
|
||||
const normalizedLanguage = localizedLanguage
|
||||
? localizedLanguage.charAt(0).toUpperCase() + localizedLanguage.slice(1)
|
||||
: languages[userLang]
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className={styles.container}>
|
||||
<Header>
|
||||
<div>
|
||||
<Title as="h4" color="red" level="h1" textTransform="capitalize">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Welcome",
|
||||
})}
|
||||
</Title>
|
||||
<Title
|
||||
data-hj-suppress
|
||||
as="h4"
|
||||
color="burgundy"
|
||||
level="h2"
|
||||
textTransform="capitalize"
|
||||
>
|
||||
{user.name}
|
||||
</Title>
|
||||
</div>
|
||||
<Button asChild intent="primary" size="small" theme="base">
|
||||
<Link prefetch={false} color="none" href={profileEdit[lang]}>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Edit profile",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
</Header>
|
||||
<div className={styles.profile}>
|
||||
<div className={styles.info}>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon
|
||||
icon="calendar_month"
|
||||
color="Icon/Interactive/Default"
|
||||
/>
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Date of Birth",
|
||||
})}
|
||||
</Body>
|
||||
<Body color="burgundy">{user.dateOfBirth}</Body>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon icon="phone" color="Icon/Interactive/Default" />
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Phone number",
|
||||
})}
|
||||
</Body>
|
||||
<Body color="burgundy">{user.phoneNumber}</Body>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon icon="globe" color="Icon/Interactive/Default" />
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Language",
|
||||
})}
|
||||
</Body>
|
||||
<Body color="burgundy">{normalizedLanguage}</Body>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon icon="mail" color="Icon/Interactive/Default" />
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Email",
|
||||
})}
|
||||
</Body>
|
||||
<Body color="burgundy">{user.email}</Body>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon
|
||||
icon="location_on"
|
||||
color="Icon/Interactive/Default"
|
||||
/>
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Address",
|
||||
})}
|
||||
</Body>
|
||||
<Body color="burgundy">{addressOutput}</Body>
|
||||
</div>
|
||||
<div className={styles.item}>
|
||||
<MaterialIcon icon="lock" color="Icon/Interactive/Default" />
|
||||
<Body color="burgundy" textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Password",
|
||||
})}
|
||||
</Body>
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
<Body color="burgundy">**********</Body>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Divider color="burgundy" opacity={8} />
|
||||
<CreditCardSlot />
|
||||
{/* <MembershipCardSlot /> */}
|
||||
<CommunicationSlot />
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
.horizontal {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.vertical {
|
||||
|
||||
@@ -9,5 +9,5 @@ export default function Divider({
|
||||
variant,
|
||||
}: DividerProps) {
|
||||
const classNames = dividerVariants({ className, color, opacity, variant })
|
||||
return <div className={classNames} />
|
||||
return <hr className={classNames} />
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user