Merged in fix/sas-flow-design-updates (pull request #1567)

Fix typography in SAS flow

* Add missing translation

* Update SAS login page typography

* Update LinkAccountFormTypography

* Update typography in OneTimePasswordForm

* Update typography of SAS link success page

* Update typography of SAS flow errors

* Update typography of SAS unlink success page

* Update typography of SAS error boundary


Approved-by: Linus Flood
This commit is contained in:
Anton Gunnarsson
2025-03-21 09:05:47 +00:00
parent d406725a65
commit c58815ec06
21 changed files with 224 additions and 174 deletions

View File

@@ -2,12 +2,12 @@
import Link from "next/link"
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { partnerSas } from "@/constants/routes/myPages"
import ErrorCircleFilledIcon from "@/components/Icons/ErrorCircleFilled"
import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import Title from "@/components/TempDesignSystem/Text/Title"
import useLang from "@/hooks/useLang"
import { SASModal, SASModalContactBlock, SASModalDivider } from "./SASModal"
@@ -19,15 +19,17 @@ export function AlreadyLinkedError() {
return (
<SASModal>
<ErrorCircleFilledIcon height={64} width={64} color="red" />
<Title as="h2" level="h1" textAlign="center" textTransform="regular">
{intl.formatMessage({ id: "Accounts are already linked" })}
</Title>
<Body textAlign="center">
{/* TODO copy */}
{intl.formatMessage({
id: "We could not connect your accounts to give you access. Please contact us and well help you resolve this issue.",
})}
</Body>
<Typography variant="Title/Subtitle/lg">
<h1>{intl.formatMessage({ id: "Accounts are already linked" })}</h1>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{/* TODO copy */}
{intl.formatMessage({
id: "We could not connect your accounts to give you access. Please contact us and well help you resolve this issue.",
})}
</p>
</Typography>
<Button theme="base" asChild>
<Link href={partnerSas[lang]}>
{intl.formatMessage({ id: "View your account" })}

View File

@@ -2,12 +2,12 @@
import { Link } from "react-aria-components"
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { profile } from "@/constants/routes/myPages"
import ErrorCircleFilledIcon from "@/components/Icons/ErrorCircleFilled"
import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import Title from "@/components/TempDesignSystem/Text/Title"
import useLang from "@/hooks/useLang"
import { SASModal, SASModalContactBlock, SASModalDivider } from "./SASModal"
@@ -19,16 +19,18 @@ export function DateOfBirthError() {
return (
<SASModal>
<ErrorCircleFilledIcon height={64} width={64} color="red" />
<Title as="h2" level="h1" textAlign="center" textTransform="regular">
{intl.formatMessage({ id: "Date of birth not matching" })}
</Title>
<Body textAlign="center">
{/* TODO copy */}
{intl.formatMessage({
id: "We could not connect your accounts to give you access. Please contact us and well help you resolve this issue.",
})}
</Body>
<Button theme="base">
<Typography variant="Title/Subtitle/lg">
<h1>{intl.formatMessage({ id: "Date of birth not matching" })}</h1>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{/* TODO copy */}
{intl.formatMessage({
id: "We could not connect your accounts to give you access. Please contact us and well help you resolve this issue.",
})}
</p>
</Typography>
<Button theme="base" asChild>
<Link href={profile[lang]}>
{intl.formatMessage({ id: "View your account" })}
</Link>

View File

@@ -2,8 +2,9 @@
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import { GenericError } from "./GenericError"
@@ -15,11 +16,13 @@ export function FailedAttemptsError() {
title={intl.formatMessage({ id: "Too many failed attempts" })}
variant="info"
>
<Body textAlign="center">
{intl.formatMessage({
id: "Please wait 1 hour before trying again.",
})}
</Body>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
id: "Please wait 1 hour before trying again.",
})}
</p>
</Typography>
<Button theme="base" disabled>
{intl.formatMessage({ id: "Send new code" })}
</Button>

View File

@@ -1,8 +1,9 @@
"use client"
import Image from "next/image"
import { Typography } from "@scandic-hotels/design-system/Typography"
import ErrorCircleFilledIcon from "@/components/Icons/ErrorCircleFilled"
import Title from "@/components/TempDesignSystem/Text/Title"
import { SASModal } from "./SASModal"
@@ -30,9 +31,9 @@ export function GenericError({
style={{ marginTop: 16 }}
/>
)}
<Title as="h3" level="h1" textAlign="center" textTransform="regular">
{title}
</Title>
<Typography variant="Title/Subtitle/lg">
<h1>{title}</h1>
</Typography>
{children}
</SASModal>
)

View File

@@ -27,6 +27,7 @@
position: relative;
padding: 0 var(--Spacing-x2);
background-color: white;
color: var(--UI-Text-Placeholder);
}
&::before {

View File

@@ -2,9 +2,9 @@
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Title from "@/components/TempDesignSystem/Text/Title"
import styles from "./SASModal.module.css"
@@ -17,9 +17,9 @@ export function SASModalDivider() {
return (
<div className={styles.divider}>
<Body asChild color="uiTextPlaceholder">
<Typography variant="Body/Paragraph/mdRegular">
<span>{intl.formatMessage({ id: "or" })}</span>
</Body>
</Typography>
</div>
)
}
@@ -31,14 +31,11 @@ export function SASModalContactBlock() {
return (
<div style={{ display: "flex", flexDirection: "column" }}>
<Title
level="h4"
as="h3"
textTransform="regular"
className={styles.contactBlockTitle}
>
{intl.formatMessage({ id: "Contact our memberservice" })}
</Title>
<Typography variant="Title/Subtitle/md">
<h4 className={styles.contactBlockTitle}>
{intl.formatMessage({ id: "Contact our memberservice" })}
</h4>
</Typography>
<Link
href={`tel:${phone.replaceAll(" ", "")}`}
textDecoration="underline"

View File

@@ -2,8 +2,9 @@
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import { GenericError } from "./GenericError"
@@ -15,11 +16,13 @@ export function TooManyCodesError() {
title={intl.formatMessage({ id: "Youve requested too many codes" })}
variant="info"
>
<Body textAlign="center">
{intl.formatMessage({
id: "Please wait 1 hour before trying again.",
})}
</Body>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
id: "Please wait 1 hour before trying again.",
})}
</p>
</Typography>
<Button theme="base" disabled>
{intl.formatMessage({ id: "Send new code" })}
</Button>

View File

@@ -2,8 +2,9 @@
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import { GenericError } from "./GenericError"
@@ -15,11 +16,13 @@ export function TooManyFailedAttemptsError() {
title={intl.formatMessage({ id: "Too many failed attempts." })}
variant="info"
>
<Body textAlign="center">
{intl.formatMessage({
id: "Please wait 1 hour before trying again.",
})}
</Body>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
id: "Please wait 1 hour before trying again.",
})}
</p>
</Typography>
<Button theme="base" disabled>
{intl.formatMessage({ id: "Send new code" })}
</Button>

View File

@@ -4,7 +4,7 @@ import * as Sentry from "@sentry/nextjs"
import { useEffect } from "react"
import { useIntl } from "react-intl"
import Body from "@/components/TempDesignSystem/Text/Body"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { GenericError } from "./components/GenericError"
import { SASModalContactBlock } from "./components/SASModal"
@@ -29,11 +29,13 @@ export default function Error({
id: "Something went wrong",
})}
>
<Body textAlign="center">
{intl.formatMessage({
id: "Please try again later",
})}
</Body>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
id: "Please try again later",
})}
</p>
</Typography>
<SASModalContactBlock />
</GenericError>
)

View File

@@ -1,4 +1,5 @@
import Body from "@/components/TempDesignSystem/Text/Body"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { getIntl } from "@/i18n"
import { AlreadyLinkedError } from "../components/AlreadyLinkedError"
@@ -39,11 +40,13 @@ export default async function Page({
id: "We could not connect your accounts",
})}
>
<Body textAlign="center">
{intl.formatMessage({
id: "We could not connect your accounts to give you access. Please contact us and well help you resolve this issue.",
})}
</Body>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
id: "We could not connect your accounts to give you access. Please contact us and well help you resolve this issue.",
})}
</p>
</Typography>
<SASModalContactBlock />
</GenericError>
)

View File

@@ -6,15 +6,14 @@ import { useTransition } from "react"
import { FormProvider, useForm } from "react-hook-form"
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { profileEdit } from "@/constants/routes/myPages"
import { ArrowRightIcon } from "@/components/Icons"
import Button from "@/components/TempDesignSystem/Button"
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
import Label from "@/components/TempDesignSystem/Form/Label"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Title from "@/components/TempDesignSystem/Text/Title"
import styles from "./link-sas.module.css"
@@ -60,28 +59,32 @@ export function LinkAccountForm({
width={182}
src="/_static/img/partner/sas/sas-campaign-logo.png"
/>
<Title level="h3" textTransform="regular">
{intl.formatMessage({ id: "Link your accounts" })}
</Title>
<Typography variant="Title/Subtitle/lg">
<h3>{intl.formatMessage({ id: "Link your accounts" })}</h3>
</Typography>
</div>
<div className={styles.dateOfBirth}>
<Body textTransform="bold">
{userDateOfBirth
? intl.formatMessage(
{
id: "Birth date: {dateOfBirth, date, ::MMMM d yyyy}",
},
{
dateOfBirth: new Date(userDateOfBirth),
}
)
: intl.formatMessage({ id: "Birth date is missing" })}
</Body>
<Label size="small" className={styles.dateOfBirthDescription}>
{intl.formatMessage({
id: "We require your birth date in order to link your Scandic account with your SAS EuroBonus account. Please check that it is correct.",
})}
</Label>
<Typography variant="Body/Paragraph/mdBold">
<p>
{userDateOfBirth
? intl.formatMessage(
{
id: "Birth date: {dateOfBirth, date, ::MMMM d yyyy}",
},
{
dateOfBirth: new Date(userDateOfBirth),
}
)
: intl.formatMessage({ id: "Birth date is missing" })}
</p>
</Typography>
<Typography variant="Label/xsRegular">
<p className={styles.dateOfBirthDescription}>
{intl.formatMessage({
id: "We require your birth date in order to link your Scandic account with your SAS EuroBonus account. Please check that it is correct.",
})}
</p>
</Typography>
<Link
href={profileEdit[params.lang]}
className={styles.dateOfBirthLink}
@@ -107,30 +110,36 @@ export function LinkAccountForm({
disabled: !userDateOfBirth,
}}
>
<Body>
{intl.formatMessage({ id: "I accept the terms and conditions" })}
</Body>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
id: "I accept the terms and conditions",
})}
</p>
</Typography>
</Checkbox>
<Body className={styles.termsDescription}>
{intl.formatMessage(
{
id: "By linking your accounts you accept the <sasScandicTermsAndConditionsLink>Scandic Friends & SAS Terms and Conditions</sasScandicTermsAndConditionsLink>. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.",
},
{
sasScandicTermsAndConditionsLink: (str) => (
<Link
// TODO correct link
href={"#"}
weight="bold"
variant="default"
textDecoration="underline"
>
{str}
</Link>
),
}
)}
</Body>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.termsDescription}>
{intl.formatMessage(
{
id: "By linking your accounts you accept the <sasScandicTermsAndConditionsLink>Scandic Friends & SAS Terms and Conditions</sasScandicTermsAndConditionsLink>. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.",
},
{
sasScandicTermsAndConditionsLink: (str) => (
<Link
// TODO correct link
href={"#"}
weight="bold"
variant="default"
textDecoration="underline"
>
{str}
</Link>
),
}
)}
</p>
</Typography>
</div>
<div className={styles.ctaContainer}>
<Button

View File

@@ -1,11 +1,11 @@
import React from "react"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { partnerSas } from "@/constants/routes/myPages"
import CheckCircle from "@/components/Icons/CheckCircle"
import { Redirect } from "@/components/Redirect"
import Body from "@/components/TempDesignSystem/Text/Body"
import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import { SASModal } from "../../components/SASModal"
@@ -21,20 +21,24 @@ export default async function SASxScandicLinkPage({
<SASModal>
<Redirect url={partnerSas[params.lang]} timeout={3000} />
<CheckCircle height={64} width={64} color="uiSemanticSuccess" />
<Title as="h2" level="h1" textAlign="center">
{intl.formatMessage({ id: "Your accounts are connected" })}
</Title>
<Typography variant="Title/Subtitle/lg">
<h1>{intl.formatMessage({ id: "Your accounts are linked" })}</h1>
</Typography>
<div>
<Body textAlign="center">
{intl.formatMessage({
id: "We successfully connected your accounts!",
})}
</Body>
<Body textAlign="center">
{intl.formatMessage({
id: "Redirecting you to my pages.",
})}
</Body>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
id: "We successfully connected your accounts!",
})}
</p>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
id: "Redirecting you to my pages.",
})}
</p>
</Typography>
</div>
</SASModal>
)

View File

@@ -2,14 +2,14 @@ import { redirect } from "next/navigation"
import React from "react"
import { z } from "zod"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { env } from "@/env/server"
import Image from "@/components/Image"
import { Redirect } from "@/components/Redirect"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import { SASModal } from "../components/SASModal"
@@ -73,10 +73,14 @@ export default async function SASxScandicLoginPage({
height="110"
style={{ marginTop: 16 }}
/>
<Title as="h2" level="h1" textTransform="regular">
{intl.formatMessage({ id: "Redirecting you to SAS" })}
</Title>
<Body textAlign="center">{intentDescriptions[parsedParams.intent]}</Body>
<Typography variant="Title/Subtitle/lg">
<h1>{intl.formatMessage({ id: "Redirecting you to SAS" })}</h1>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p style={{ textAlign: "center" }}>
{intentDescriptions[parsedParams.intent]}
</p>
</Typography>
<Footnote textAlign="center">
{intl.formatMessage<
React.ReactNode,

View File

@@ -6,14 +6,12 @@ import { useParams, useRouter } from "next/navigation"
import { type ReactNode, useState, useTransition } from "react"
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { trpc } from "@/lib/trpc/client"
import ErrorCircleFilledIcon from "@/components/Icons/ErrorCircleFilled"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import { GenericError } from "../components/GenericError"
import { SASModal, SASModalContactBlock } from "../components/SASModal"
@@ -63,7 +61,9 @@ export default function OneTimePasswordForm({
return (
<GenericError title={title}>
<Body textAlign="center">{body}</Body>
<Typography variant="Body/Paragraph/mdRegular">
<p style={{ textAlign: "center" }}>{body}</p>
</Typography>
<SASModalContactBlock />
</GenericError>
)
@@ -116,7 +116,7 @@ export default function OneTimePasswordForm({
onClick={handleRequestNewOtp}
color="red"
variant="default"
size="tiny"
size="small"
className={disableResend ? styles["disabled-link"] : ""}
>
{str}
@@ -141,10 +141,12 @@ export default function OneTimePasswordForm({
return (
<SASModal>
<Subtitle textAlign={"center"}>{heading}</Subtitle>
<div>
<Body textAlign={"center"}>{ingress}</Body>
</div>
<Typography variant="Title/Subtitle/lg">
<h1>{heading}</h1>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p>{ingress}</p>
</Typography>
<OTPInput
autoFocus
@@ -169,21 +171,27 @@ export default function OneTimePasswordForm({
{errorMessage && (
<div className={styles["error-message"]}>
<ErrorCircleFilledIcon height={20} width={20} color="red" />
<Caption color="red">{errorMessage}</Caption>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p style={{ color: "var(--Scandic-Red-60)" }}>{errorMessage}</p>
</Typography>
</div>
)}
<div>
<Footnote>{footnote}</Footnote>
<Footnote>
{intl.formatMessage(
{
id: "Didn't receive a code? <resendOtpLink>Resend code</resendOtpLink>",
},
{
resendOtpLink: getResendOtpLink,
}
)}
</Footnote>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>{footnote}</p>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{intl.formatMessage(
{
id: "Didn't receive a code? <resendOtpLink>Resend code</resendOtpLink>",
},
{
resendOtpLink: getResendOtpLink,
}
)}
</p>
</Typography>
</div>
</SASModal>
)

View File

@@ -1,11 +1,11 @@
import React from "react"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { overview } from "@/constants/routes/myPages"
import CheckCircle from "@/components/Icons/CheckCircle"
import { Redirect } from "@/components/Redirect"
import Body from "@/components/TempDesignSystem/Text/Body"
import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import { SASModal } from "../../components/SASModal"
@@ -21,15 +21,17 @@ export default async function SASxScandicUnlinkSuccessPage({
<SASModal>
<Redirect url={overview[params.lang]} timeout={3000} />
<CheckCircle height={64} width={64} color="uiSemanticSuccess" />
<Title as="h2" level="h1" textAlign="center">
{intl.formatMessage({ id: "Your accounts are now unlinked" })}
</Title>
<Typography variant="Title/Subtitle/lg">
<h1>{intl.formatMessage({ id: "Your accounts are now unlinked" })}</h1>
</Typography>
<div>
<Body textAlign="center">
{intl.formatMessage({
id: "Redirecting you to My Pages.",
})}
</Body>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
id: "Redirecting you to My Pages.",
})}
</p>
</Typography>
</div>
</SASModal>
)