Merged in fix/SW-315-design-fixes-my-pages (pull request #825)

fix(SW-315): formatting numbers via locale, fixed a few padding issues

Approved-by: Michael Zetterberg
Approved-by: Simon.Emanuelsson
This commit is contained in:
Christian Andolf
2024-11-08 08:32:18 +00:00
30 changed files with 85 additions and 88 deletions

View File

@@ -18,7 +18,7 @@ export default async function MyPages({
setLang(params.lang)
const accountPageRes = await serverClient().contentstack.accountPage.get()
const { formatMessage } = await getIntl()
const intl = await getIntl()
if (!accountPageRes) {
return null
@@ -33,7 +33,7 @@ export default async function MyPages({
{accountPage.content?.length ? (
<Blocks blocks={accountPage.content} />
) : (
<p>{formatMessage({ id: "No content published" })}</p>
<p>{intl.formatMessage({ id: "No content published" })}</p>
)}
</main>
<TrackingSDK pageData={tracking} />

View File

@@ -13,15 +13,15 @@ export default async function CommunicationSlot({
}: PageArgs<LangParams>) {
setLang(params.lang)
const { formatMessage } = await getIntl()
const intl = await getIntl()
return (
<section className={styles.container}>
<article className={styles.content}>
<Subtitle type="two" color="black">
{formatMessage({ id: "My communication preferences" })}
{intl.formatMessage({ id: "My communication preferences" })}
</Subtitle>
<Body color="black">
{formatMessage({
{intl.formatMessage({
id: "Tell us what information and updates you'd like to receive, and how, by clicking the link below.",
})}
</Body>

View File

@@ -13,17 +13,17 @@ import { LangParams, PageArgs } from "@/types/params"
export default async function CreditCardSlot({ params }: PageArgs<LangParams>) {
setLang(params.lang)
const { formatMessage } = await getIntl()
const intl = await getIntl()
const creditCards = await serverClient().user.creditCards()
return (
<section className={styles.container}>
<article className={styles.content}>
<Subtitle type="two" color="black">
{formatMessage({ id: "My payment cards" })}
{intl.formatMessage({ id: "My payment cards" })}
</Subtitle>
<Body color="black">
{formatMessage({
{intl.formatMessage({
id: "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.",
})}
</Body>

View File

@@ -15,14 +15,14 @@ export default async function MembershipCardSlot({
params,
}: PageArgs<LangParams>) {
setLang(params.lang)
const { formatMessage } = await getIntl()
const intl = await getIntl()
const membershipCards = await getMembershipCards()
return (
<section className={styles.container}>
<article className={styles.content}>
<Subtitle color="black">
{formatMessage({ id: "My membership cards" })}
{intl.formatMessage({ id: "My membership cards" })}
</Subtitle>
</article>
{membershipCards &&
@@ -41,7 +41,7 @@ export default async function MembershipCardSlot({
<Link href="#" variant="icon">
<PlusCircleIcon color="burgundy" />
<Body color="burgundy" textTransform="underlined">
{formatMessage({ id: "Add new card" })}
{intl.formatMessage({ id: "Add new card" })}
</Body>
</Link>
</section>

View File

@@ -24,7 +24,7 @@ import { LangParams, PageArgs } from "@/types/params"
export default async function Profile({ params }: PageArgs<LangParams>) {
setLang(params.lang)
const { formatMessage } = await getIntl()
const intl = await getIntl()
const user = await getProfile()
if (!user || "error" in user) {
return null
@@ -37,7 +37,7 @@ export default async function Profile({ params }: PageArgs<LangParams>) {
<Header>
<hgroup>
<Title as="h4" color="red" level="h1" textTransform="capitalize">
{formatMessage({ id: "Welcome" })}
{intl.formatMessage({ id: "Welcome" })}
</Title>
<Title as="h4" color="burgundy" level="h2" textTransform="capitalize">
{user.name}
@@ -45,7 +45,7 @@ export default async function Profile({ params }: PageArgs<LangParams>) {
</hgroup>
<Button asChild intent="primary" size="small" theme="base">
<Link prefetch={false} color="none" href={profileEdit[params.lang]}>
{formatMessage({ id: "Edit profile" })}
{intl.formatMessage({ id: "Edit profile" })}
</Link>
</Button>
</Header>
@@ -54,35 +54,35 @@ export default async function Profile({ params }: PageArgs<LangParams>) {
<div className={styles.item}>
<CalendarIcon color="burgundy" />
<Body color="burgundy" textTransform="bold">
{formatMessage({ id: "Date of Birth" })}
{intl.formatMessage({ id: "Date of Birth" })}
</Body>
<Body color="burgundy">{user.dateOfBirth}</Body>
</div>
<div className={styles.item}>
<PhoneIcon color="burgundy" />
<Body color="burgundy" textTransform="bold">
{formatMessage({ id: "Phone number" })}
{intl.formatMessage({ id: "Phone number" })}
</Body>
<Body color="burgundy">{user.phoneNumber}</Body>
</div>
<div className={styles.item}>
<GlobeIcon color="burgundy" />
<Body color="burgundy" textTransform="bold">
{formatMessage({ id: "Language" })}
{intl.formatMessage({ id: "Language" })}
</Body>
<Body color="burgundy">{language?.label ?? defaultLanguage}</Body>
</div>
<div className={styles.item}>
<EmailIcon color="burgundy" />
<Body color="burgundy" textTransform="bold">
{formatMessage({ id: "Email" })}
{intl.formatMessage({ id: "Email" })}
</Body>
<Body color="burgundy">{user.email}</Body>
</div>
<div className={styles.item}>
<LocationIcon color="burgundy" />
<Body color="burgundy" textTransform="bold">
{formatMessage({ id: "Address" })}
{intl.formatMessage({ id: "Address" })}
</Body>
<Body color="burgundy">
{user.address.streetAddress
@@ -100,7 +100,7 @@ export default async function Profile({ params }: PageArgs<LangParams>) {
<div className={styles.item}>
<LockIcon color="burgundy" />
<Body color="burgundy" textTransform="bold">
{formatMessage({ id: "Password" })}
{intl.formatMessage({ id: "Password" })}
</Body>
<Body color="burgundy">**********</Body>
</div>

View File

@@ -13,13 +13,13 @@ export default async function MembershipNumber({
color,
membership,
}: MembershipNumberProps) {
const { formatMessage } = await getIntl()
const intl = await getIntl()
const classNames = membershipNumberVariants({ className, color })
return (
<div className={classNames}>
<Caption color="pale">
{formatMessage({ id: "Membership ID" })}
{intl.formatMessage({ id: "Membership ID" })}
{": "}
</Caption>
<span className={styles.icon}>

View File

@@ -18,7 +18,7 @@ export default async function Friend({
membership,
name,
}: FriendProps) {
const { formatMessage } = await getIntl()
const intl = await getIntl()
if (!membership?.membershipLevel) {
return null
}
@@ -28,7 +28,7 @@ export default async function Friend({
<section className={styles.friend}>
<header className={styles.header}>
<Body color="white" textTransform="bold" textAlign="center">
{formatMessage(
{intl.formatMessage(
isHighestLevel
? { id: "Highest level" }
: { id: `Level ${membershipLevels[membership.membershipLevel]}` }

View File

@@ -4,7 +4,6 @@ import { dt } from "@/lib/dt"
import Body from "@/components/TempDesignSystem/Text/Body"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import { formatNumber } from "@/utils/format"
import { getMembership } from "@/utils/user"
import type { UserProps } from "@/types/components/myPages/user"
@@ -27,7 +26,7 @@ export default async function ExpiringPoints({ user }: UserProps) {
{intl.formatMessage(
{ id: "spendable points expiring by" },
{
points: formatNumber(membership.pointsToExpire),
points: intl.formatNumber(membership.pointsToExpire),
date: d.format(dateFormat),
}
)}

View File

@@ -44,7 +44,14 @@ async function PointsColumn({
title,
subtitle,
}: PointsColumnProps) {
const { formatMessage } = await getIntl()
const intl = await getIntl()
let number = "N/A"
if (typeof points === "number") {
number = intl.formatNumber(points)
} else if (typeof nights === "number") {
number = intl.formatNumber(nights)
}
return (
<article className={styles.article}>
@@ -54,16 +61,16 @@ async function PointsColumn({
textAlign="center"
className={styles.firstRow}
>
{formatMessage({
{intl.formatMessage({
id: title,
})}
</Body>
<Title color="white" level="h2" textAlign="center">
{points ?? nights ?? "N/A"}
{number}
</Title>
{subtitle ? (
<Body color="white" textAlign="center">
{formatMessage({ id: subtitle })}
{intl.formatMessage({ id: subtitle })}
</Body>
) : null}
</article>

View File

@@ -10,7 +10,7 @@ import { NextLevelPointsColumn, YourPointsColumn } from "./PointsColumn"
import { UserProps } from "@/types/components/myPages/user"
export default async function Points({ user }: UserProps) {
const { formatMessage } = await getIntl()
const intl = await getIntl()
const membership = getMembership(user.memberships)
@@ -27,7 +27,7 @@ export default async function Points({ user }: UserProps) {
{nextLevel && (
<NextLevelPointsColumn
points={membership?.pointsRequiredToNextlevel}
subtitle={`${formatMessage({ id: "next level:" })} ${nextLevel.name}`}
subtitle={`${intl.formatMessage({ id: "next level:" })} ${nextLevel.name}`}
/>
)}
{/* TODO: Show NextLevelNightsColumn when nightsToTopTier data is correct from Antavo */}

View File

@@ -1,7 +1,6 @@
import { useIntl } from "react-intl"
import Body from "@/components/TempDesignSystem/Text/Body"
import { formatNumber } from "@/utils/format"
import { awardPointsVariants } from "./awardPointsVariants"
@@ -34,7 +33,7 @@ export default function AwardPoints({
return (
<Body textTransform="bold" className={classNames}>
{isCalculated
? formatNumber(awardPoints)
? intl.formatNumber(awardPoints)
: intl.formatMessage({ id: "Points being calculated" })}
</Body>
)

View File

@@ -17,7 +17,7 @@ import { LangParams } from "@/types/params"
/* TODO */
export default async function Points({ user, lang }: UserProps & LangParams) {
const { formatMessage } = await getIntl()
const intl = await getIntl()
const membership = getMembership(user.memberships)
if (!membership?.nextLevel || !MembershipLevelEnum[membership.nextLevel]) {
@@ -34,13 +34,13 @@ export default async function Points({ user, lang }: UserProps & LangParams) {
{membership?.currentPoints ? (
<StayOnLevelColumn
points={membership?.currentPoints} //TODO
subtitle={`${formatMessage({ id: "by" })} ${membership?.expirationDate}`}
subtitle={`${intl.formatMessage({ id: "by" })} ${membership?.expirationDate}`}
/>
) : (
<>
<NextLevelPointsColumn
points={membership?.pointsRequiredToNextlevel}
subtitle={`${formatMessage({ id: "next level:" })} ${nextLevel.name}`}
subtitle={`${intl.formatMessage({ id: "next level:" })} ${nextLevel.name}`}
/>
{membership?.nightsToTopTier && (
<NextLevelNightsColumn

View File

@@ -4,11 +4,11 @@ import { getIntl } from "@/i18n"
import styles from "./emptyPreviousStays.module.css"
export default async function EmptyPreviousStaysBlock() {
const { formatMessage } = await getIntl()
const intl = await getIntl()
return (
<section className={styles.container}>
<Title as="h4" level="h3" color="red" textAlign="center">
{formatMessage({
{intl.formatMessage({
id: "You have no previous stays.",
})}
</Title>

View File

@@ -13,7 +13,7 @@ export default function ShowMoreButton({
disabled,
loadMoreData,
}: ShowMoreButtonParams) {
const { formatMessage } = useIntl()
const intl = useIntl()
return (
<div className={styles.container}>
<Button
@@ -25,7 +25,7 @@ export default function ShowMoreButton({
intent="text"
>
<ChevronDownIcon />
{formatMessage({ id: "Show more" })}
{intl.formatMessage({ id: "Show more" })}
</Button>
</div>
)

View File

@@ -10,14 +10,14 @@ import { getLang } from "@/i18n/serverContext"
import styles from "./emptyUpcomingStays.module.css"
export default async function EmptyUpcomingStaysBlock() {
const { formatMessage } = await getIntl()
const intl = await getIntl()
return (
<section className={styles.container}>
<div className={styles.titleContainer}>
<Title as="h4" level="h3" color="red" className={styles.title}>
{formatMessage({ id: "You have no upcoming stays." })}
{intl.formatMessage({ id: "You have no upcoming stays." })}
<span className={styles.burgundyTitle}>
{formatMessage({ id: "Where should you go next?" })}
{intl.formatMessage({ id: "Where should you go next?" })}
</span>
</Title>
</div>
@@ -26,7 +26,7 @@ export default async function EmptyUpcomingStaysBlock() {
className={styles.link}
color="peach80"
>
{formatMessage({ id: "Get inspired" })}
{intl.formatMessage({ id: "Get inspired" })}
<ArrowRightIcon color="peach80" />
</Link>
</section>

View File

@@ -10,14 +10,14 @@ import { getLang } from "@/i18n/serverContext"
import styles from "./emptyUpcomingStays.module.css"
export default async function EmptyUpcomingStaysBlock() {
const { formatMessage } = await getIntl()
const intl = await getIntl()
return (
<section className={styles.container}>
<div className={styles.titleContainer}>
<Title as="h4" level="h3" color="red" className={styles.title}>
{formatMessage({ id: "You have no upcoming stays." })}
{intl.formatMessage({ id: "You have no upcoming stays." })}
<span className={styles.burgundyTitle}>
{formatMessage({ id: "Where should you go next?" })}
{intl.formatMessage({ id: "Where should you go next?" })}
</span>
</Title>
</div>
@@ -26,7 +26,7 @@ export default async function EmptyUpcomingStaysBlock() {
className={styles.link}
color="peach80"
>
{formatMessage({ id: "Get inspired" })}
{intl.formatMessage({ id: "Get inspired" })}
<ArrowRightIcon color="peach80" />
</Link>
</section>

View File

@@ -7,10 +7,10 @@ import { useIntl } from "react-intl"
import styles from "./bookingButton.module.css"
export default function BookingButton({ href }: { href: string }) {
const { formatMessage } = useIntl()
const intl = useIntl()
return (
<a className={styles.button} href={href}>
{formatMessage({ id: "Book" })}
{intl.formatMessage({ id: "Book" })}
</a>
)
}

View File

@@ -22,7 +22,7 @@ export default function MyPagesMobileDropdown({
}: {
navigation: Navigation
}) {
const { formatMessage } = useIntl()
const intl = useIntl()
const lang = useLang()
const { toggleDropdown, isMyPagesMobileMenuOpen } = useDropdownStore()
@@ -69,7 +69,7 @@ export default function MyPagesMobileDropdown({
color="burgundy"
variant="myPageMobileDropdown"
>
{formatMessage({ id: "Log out" })}
{intl.formatMessage({ id: "Log out" })}
</Link>
</li>
) : null}

View File

@@ -21,7 +21,7 @@ export default async function TopMenu({
links,
languageSwitcher,
}: TopMenuProps) {
const { formatMessage } = await getIntl()
const intl = await getIntl()
const user = await getName()
return (
<div className={styles.topMenu}>
@@ -60,7 +60,7 @@ export default async function TopMenu({
className={styles.sessionLink}
prefetch={false}
>
{formatMessage({ id: "Log out" })}
{intl.formatMessage({ id: "Log out" })}
</Link>
</>
) : (
@@ -69,7 +69,7 @@ export default async function TopMenu({
trackingId="loginStartTopMenu"
className={`${styles.sessionLink} ${styles.loginLink}`}
>
{formatMessage({ id: "Log in" })}
{intl.formatMessage({ id: "Log in" })}
</LoginButton>
)}
</li>

View File

@@ -20,7 +20,7 @@ function SocialIcon({ iconName }: SocialIconsProps) {
export default async function FooterDetails() {
const lang = getLang()
const { formatMessage } = await getIntl()
const intl = await getIntl()
// preloaded
const footer = await getFooter()
const languages = await getLanguageSwitcher()
@@ -58,7 +58,7 @@ export default async function FooterDetails() {
<div className={styles.copyrightContainer}>
<Footnote textTransform="uppercase">
© {currentYear}{" "}
{formatMessage({ id: "Copyright all rights reserved" })}
{intl.formatMessage({ id: "Copyright all rights reserved" })}
</Footnote>
</div>
<div className={styles.navigationContainer}>

View File

@@ -8,7 +8,6 @@ import { serverClient } from "@/lib/trpc/server"
import LoginButton from "@/components/LoginButton"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import Avatar from "../Avatar"
import MyPagesMenu from "../MyPagesMenu"
@@ -17,7 +16,6 @@ import MyPagesMobileMenu from "../MyPagesMobileMenu"
import styles from "./myPagesMenuWrapper.module.css"
export default async function MyPagesMenuWrapper() {
const lang = getLang()
const [intl, myPagesNavigation, user, membership] = await Promise.all([
getIntl(),
getMyPagesNavigation(),

View File

@@ -13,7 +13,6 @@ import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import useLang from "@/hooks/useLang"
import { formatNumber } from "@/utils/format"
import styles from "./summary.module.css"
@@ -106,7 +105,9 @@ export default function Summary({
{intl.formatMessage(
{ id: "{amount} {currency}" },
{
amount: formatNumber(parseInt(room.localPrice.price ?? "0")),
amount: intl.formatNumber(
parseInt(room.localPrice.price ?? "0")
),
currency: room.localPrice.currency,
}
)}
@@ -202,7 +203,7 @@ export default function Summary({
{intl.formatMessage(
{ id: "{amount} {currency}" },
{
amount: formatNumber(totalPrice.local),
amount: intl.formatNumber(totalPrice.local),
currency: room.localPrice.currency,
}
)}
@@ -212,7 +213,7 @@ export default function Summary({
{intl.formatMessage(
{ id: "{amount} {currency}" },
{
amount: formatNumber(totalPrice.euro),
amount: intl.formatNumber(totalPrice.euro),
currency: room.euroPrice.currency,
}
)}

View File

@@ -13,7 +13,7 @@ import styles from "./sidebar.module.css"
export default async function SidebarMyPages() {
const navigation = await getMyPagesNavigation()
const { formatMessage } = await getIntl()
const intl = await getIntl()
return (
<aside className={styles.sidebar}>
@@ -46,7 +46,7 @@ export default async function SidebarMyPages() {
size="small"
variant="sidebar"
>
{formatMessage({ id: "Log out" })}
{intl.formatMessage({ id: "Log out" })}
</Link>
</li>
) : null}

View File

@@ -12,17 +12,19 @@ export default function DeleteCreditCardButton({
}: {
creditCardId: string
}) {
const { formatMessage } = useIntl()
const intl = useIntl()
const trpcUtils = trpc.useUtils()
const deleteCreditCardMutation = trpc.user.creditCard.delete.useMutation({
onSuccess() {
trpcUtils.user.creditCards.invalidate()
toast.success(formatMessage({ id: "Credit card deleted successfully" }))
toast.success(
intl.formatMessage({ id: "Credit card deleted successfully" })
)
},
onError() {
toast.error(
formatMessage({
intl.formatMessage({
id: "Failed to delete credit card, please try again later.",
})
)

View File

@@ -1,6 +1,6 @@
.header {
display: grid;
gap: var(--Spacing-x1);
gap: var(--Spacing-x1) var(--Spacing-x5);
grid-template-columns: 1fr;
align-items: baseline;
}

View File

@@ -1,11 +1,11 @@
import { getIntl } from "@/i18n"
export default async function SkipToMainContent() {
const { formatMessage } = await getIntl()
const intl = await getIntl()
return (
<div className="navigation--skip-to-content">
<a data-js="skip-to-content" href="#maincontent">
{formatMessage({ id: "Skip to main content" })}
{intl.formatMessage({ id: "Skip to main content" })}
</a>
</div>
)

View File

@@ -34,7 +34,7 @@ export default function CountrySelect({
readOnly = false,
registerOptions = {},
}: CountryProps) {
const { formatMessage } = useIntl()
const intl = useIntl()
const [rootDiv, setRootDiv] = useState<CountryPortalContainer>(undefined)
function setRef(node: CountryPortalContainerArgs) {
@@ -53,13 +53,12 @@ export default function CountrySelect({
setValue(name, country)
}
const selectCountryLabel = formatMessage({ id: "Select a country" })
const selectCountryLabel = intl.formatMessage({ id: "Select a country" })
return (
<div className={`${styles.container} ${className}`} ref={setRef}>
<ComboBox
aria-label={formatMessage({ id: "Select country of residence" })}
className={styles.select}
aria-label={intl.formatMessage({ id: "Select country of residence" })}
isInvalid={fieldState.invalid}
isReadOnly={readOnly}
isRequired={!!registerOptions?.required}

View File

@@ -36,7 +36,7 @@ export default function Phone({
required: true,
},
}: PhoneProps) {
const { formatMessage } = useIntl()
const intl = useIntl()
const { control, setValue, trigger } = useFormContext()
const phone = useWatch({ name })
@@ -95,7 +95,7 @@ export default function Phone({
data-testid="country-selector"
>
<Label required={!!registerOptions.required} size="small">
{formatMessage({ id: "Country code" })}
{intl.formatMessage({ id: "Country code" })}
</Label>
<span className={styles.selectContainer}>
{props.children}

View File

@@ -10,14 +10,14 @@ import { webviewSearchParams } from "@/utils/webviews"
import styles from "./linkToOverview.module.css"
export default async function LinkToOverview() {
const { formatMessage } = await getIntl()
const intl = await getIntl()
const searchParams = webviewSearchParams()
const overviewHref = `${overview[getLang()]}?${searchParams.toString()}`
return (
<Link className={styles.overviewLink} href={overviewHref}>
<ArrowLeft height={20} width={20} />{" "}
{formatMessage({ id: "Go back to overview" })}
{intl.formatMessage({ id: "Go back to overview" })}
</Link>
)
}

View File

@@ -1,8 +0,0 @@
import { Lang } from "@/constants/languages"
/// Function to format numbers with space as thousands separator
export function formatNumber(num: number) {
// sv hardcoded to force space on thousands
const formatter = new Intl.NumberFormat(Lang.sv)
return formatter.format(num)
}