Merged in feat/link-employment-route (pull request #2012)

feat(LOY-229): New Link Employment page

* feat(LOY-229): Ship Link Employment page

* fix(LOY-229): review fixes

* fix(LOY-229): update Button component props for better styling consistency

* fix(LOY-229): update ButtonLink href to use linkEmployment route


Approved-by: Christian Andolf
This commit is contained in:
Chuma Mcphoy (We Ahead)
2025-05-09 07:51:27 +00:00
parent 7af4d3be1e
commit 9ac5e43f0f
6 changed files with 288 additions and 2 deletions

View File

@@ -0,0 +1,3 @@
import { ProtectedLayout } from "@/components/ProtectedLayout"
export default ProtectedLayout

View File

@@ -0,0 +1,120 @@
.pageWrapper {
min-height: 100vh;
position: relative;
display: flex;
flex-direction: column;
}
.backgroundImage {
object-fit: cover;
z-index: -1;
}
.contentContainer {
position: relative;
z-index: 10;
display: flex;
flex-direction: column;
min-height: 100vh;
background-color: transparent;
}
.nav {
padding: var(--Spacing-x2);
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
background-color: var(--Background-Secondary);
}
.navBackText {
display: none;
}
@media screen and (min-width: 768px) {
.navBackText {
display: block;
}
}
.logoContainer {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.mainContent {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding-left: var(--Spacing-x3);
padding-right: var(--Spacing-x3);
}
.card {
max-width: 580px;
margin-left: auto;
margin-right: auto;
background: var(--Base-Background-Primary-Normal);
padding: var(--Spacing-x5);
border-radius: var(--Corner-radius-lg);
display: grid;
gap: var(--Spacing-x3);
}
.formElements {
display: flex;
flex-direction: column;
gap: var(--Spacing-x3);
}
.checkboxContainer {
display: flex;
flex-direction: column;
gap: var(--Spacing-x1);
}
.checkboxWrapper {
display: flex;
align-items: center;
gap: var(--Spacing-x-one-and-half);
cursor: pointer;
}
.checkbox {
width: 24px;
height: 24px;
min-width: 24px;
border: 1px solid var(--UI-Input-Controls-Border-Normal);
border-radius: var(--Corner-radius-sm);
transition: all 0.3s;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--UI-Input-Controls-Surface-Normal);
flex-shrink: 0;
forced-color-adjust: none;
}
.checkboxWrapper[data-selected="true"] .checkbox {
border-color: var(--UI-Input-Controls-Fill-Selected);
background-color: var(--UI-Input-Controls-Fill-Selected);
}
.checkboxWrapper[data-focus-visible="true"] .checkbox {
outline: 2px solid var(--UI-Input-Controls-Fill-Selected);
outline-offset: 1px;
}
.termsTextFull {
padding-left: var(--Spacing-x5);
}
.link {
color: var(--Text-Default);
text-decoration: underline;
font-weight: var(--Font-weight-Bold);
}

View File

@@ -0,0 +1,139 @@
"use client"
import Image from "next/image"
import { useState } from "react"
import { Checkbox as AriaCheckbox } from "react-aria-components"
import { useIntl } from "react-intl"
import { Button } from "@scandic-hotels/design-system/Button"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import ScandicLogoIcon from "@scandic-hotels/design-system/Icons/ScandicLogoIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { employeeBenefits } from "@/constants/routes/dtmc"
import ButtonLink from "@/components/ButtonLink"
import useLang from "@/hooks/useLang"
import styles from "./linkEmploymentPage.module.css"
export default function LinkEmploymentPage() {
const lang = useLang()
const intl = useIntl()
const [isChecked, setIsChecked] = useState(false)
const linkMyEmploymentText = intl.formatMessage({
defaultMessage: "Link my employment",
})
return (
<div className={styles.pageWrapper}>
<Image
src="/_static/img/Scandic_Computer_Coffee.png"
alt=""
fill
className={styles.backgroundImage}
priority
/>
<div className={styles.contentContainer}>
<nav className={styles.nav}>
<ButtonLink href={employeeBenefits[lang]} variant="Text">
<MaterialIcon
icon="chevron_left"
size={20}
className={styles.backArrow}
/>
<span className={styles.navBackText}>
{intl.formatMessage({
defaultMessage: "Go back",
})}
</span>
</ButtonLink>
<div className={styles.logoContainer}>
<ScandicLogoIcon
color="Icon/Interactive/Accent"
height="20px"
width="94px"
/>
</div>
</nav>
<main className={styles.mainContent}>
<div className={styles.card}>
<Typography variant="Title/Subtitle/lg">
<h1 className={styles.heading}>
{intl.formatMessage({
defaultMessage: "Link your employment to access benefits",
})}
</h1>
</Typography>
<div className={styles.formElements}>
<div className={styles.checkboxContainer}>
<AriaCheckbox
isSelected={isChecked}
onChange={setIsChecked}
className={styles.checkboxWrapper}
>
{({ isSelected: isAriaSelected }) => (
<>
<span className={styles.checkbox}>
{isAriaSelected && (
<MaterialIcon icon="check" color="Icon/Inverted" />
)}
</span>
<Typography variant="Body/Paragraph/mdRegular">
<span>
{intl.formatMessage({
defaultMessage: "I accept the terms and conditions",
})}
</span>
</Typography>
</>
)}
</AriaCheckbox>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.termsTextFull}>
{intl.formatMessage(
{
defaultMessage:
"By accepting the {termsLink}, I agree to link my employment to access benefits. The connection will remain active during my employment or until I opt out by sending an email to Scandic's customer service.",
},
{
termsLink: (
// TODO: Update with actual URL for terms and conditions.
<a href={"#"} className={styles.link}>
{intl.formatMessage({
defaultMessage:
"Scandic Family Terms and Conditions",
})}
</a>
),
}
)}
</p>
</Typography>
</div>
{isChecked ? (
<ButtonLink
href={"#"} // TODO: Udpate with actual URL for linking employment.
>
{linkMyEmploymentText}
</ButtonLink>
) : (
<Button
variant="Primary"
typography="Body/Paragraph/mdRegular"
isDisabled
>
{linkMyEmploymentText}
</Button>
)}
</div>
</div>
</main>
</div>
</div>
)
}

View File

@@ -2,6 +2,7 @@ import React from "react"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { linkEmployment } from "@/constants/routes/dtmc"
import { login } from "@/constants/routes/handleAuth"
import { signup } from "@/constants/routes/signup"
@@ -60,8 +61,12 @@ export default async function EmployeeBenefitsCallToActions() {
return (
<div className={styles.container}>
{/*/ TODO [LOY-229]: Update href once we have new auth url. */}
<ButtonLink href="#" size="Medium" variant="Tertiary" color="Primary">
<ButtonLink
href={linkEmployment[lang]}
size="Medium"
variant="Tertiary"
color="Primary"
>
{intl.formatMessage({
defaultMessage: "Link Employment",
})}

View File

@@ -0,0 +1,19 @@
import type { LangRoute } from "@/types/routes"
export const employeeBenefits: LangRoute = {
en: "/en/employee-benefits",
sv: "/sv/employee-benefits",
no: "/no/employee-benefits",
fi: "/fi/employee-benefits",
da: "/da/employee-benefits",
de: "/de/employee-benefits",
}
export const linkEmployment: LangRoute = {
en: "/en/link-employment",
sv: "/sv/link-employment",
no: "/no/link-employment",
fi: "/fi/link-employment",
da: "/da/link-employment",
de: "/de/link-employment",
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 MiB