feat(WEB-220): label translations
This commit is contained in:
@@ -6,8 +6,6 @@ import Navigation from "./Navigation"
|
||||
|
||||
import styles from "./footer.module.css"
|
||||
|
||||
import type { LangParams } from "@/types/params"
|
||||
|
||||
export default async function Footer() {
|
||||
const footerData = await serverClient().contentstack.config.footer()
|
||||
return (
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
"use client"
|
||||
|
||||
import "@scandic-hotels/design-system/current/style.css"
|
||||
|
||||
import { _ } from "@/lib/translation"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import styles from "./bookingButton.module.css"
|
||||
|
||||
export default function BookingButton({ href }: { href: string }) {
|
||||
const { formatMessage } = useIntl()
|
||||
return (
|
||||
<a className={styles.button} href={href}>
|
||||
{_("Book")}
|
||||
{formatMessage({ id: "Book" })}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use client"
|
||||
import { useState } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { login } from "@/constants/routes/handleAuth"
|
||||
import { myPages } from "@/constants/routes/myPages"
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import Image from "@/components/Image"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
@@ -25,6 +25,7 @@ export function MainMenu({
|
||||
isLoggedIn,
|
||||
lang,
|
||||
}: MainMenuProps) {
|
||||
const intl = useIntl()
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
|
||||
function toogleIsOpen() {
|
||||
@@ -78,7 +79,7 @@ export function MainMenu({
|
||||
className={styles.mobileLinkButton}
|
||||
href={myPages[lang]}
|
||||
>
|
||||
{_("My pages")}
|
||||
{intl.formatMessage({ id: "My pages" })}
|
||||
</Link>
|
||||
</li>
|
||||
</>
|
||||
@@ -98,7 +99,7 @@ export function MainMenu({
|
||||
className={styles.mobileLinkButton}
|
||||
href={login[lang]}
|
||||
>
|
||||
{_("Log in")}
|
||||
{intl.formatMessage({ id: "Log in" })}
|
||||
</Link>
|
||||
</li>
|
||||
</>
|
||||
@@ -109,7 +110,7 @@ export function MainMenu({
|
||||
</li>
|
||||
<li className={styles.mobileLinkRow}>
|
||||
<a className={styles.mobileLinkButton} href="">
|
||||
{_("Find booking")}
|
||||
{intl.formatMessage({ id: "Find booking" })}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Link from "next/link"
|
||||
|
||||
import Image from "@/components/Image"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
|
||||
import styles from "./jsontohtml.module.css"
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import Header from "@/components/MyPages/Blocks/Header"
|
||||
import Card from "@/components/TempDesignSystem/Card"
|
||||
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./howItWorks.module.css"
|
||||
|
||||
export default function HowItWorks() {
|
||||
export default async function HowItWorks() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<Title level="h3">{_("How it works Placeholder")}</Title>
|
||||
<Title level="h3">{formatMessage({ id: "How it works" })}</Title>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
import { useParams } from "next/navigation"
|
||||
import { Check } from "react-feather"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import Image from "@/components/Image"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
@@ -18,31 +18,38 @@ import styles from "./loyaltyLevels.module.css"
|
||||
import type { Level, LevelCardProps } from "@/types/components/loyalty/blocks"
|
||||
|
||||
export default function LoyaltyLevels() {
|
||||
const { lang } = useParams()
|
||||
const params = useParams()
|
||||
const lang = params.lang as Lang
|
||||
const { formatMessage } = useIntl()
|
||||
|
||||
const { levels } = levelsData[lang as Lang]
|
||||
const { levels } = levelsData[lang]
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<div className={styles.cardContainer}>
|
||||
{levels.map((level: Level) => (
|
||||
<LevelCard key={level.tier} level={level} />
|
||||
<LevelCard
|
||||
key={level.tier}
|
||||
formatMessage={formatMessage}
|
||||
lang={lang}
|
||||
level={level}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button intent="primary" asChild>
|
||||
<Link href={"/compare-all-levels"}>{_("Compare all levels")}</Link>
|
||||
<Link href={`/${lang}/compare-all-levels`}>
|
||||
{formatMessage({ id: "Compare all levels" })}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function LevelCard({ level }: LevelCardProps) {
|
||||
const { lang } = useParams()
|
||||
|
||||
function LevelCard({ formatMessage, lang, level }: LevelCardProps) {
|
||||
const pointsString = `${level.requiredPoints.toLocaleString(lang)}p`
|
||||
const qualifications = level.requiredNights
|
||||
? `${pointsString} ${_("or")} ${level.requiredNights} ${_("nights")}`
|
||||
? `${pointsString} ${formatMessage({ id: "or" })} ${level.requiredNights} ${formatMessage({ id: "nights" })}`
|
||||
: pointsString
|
||||
return (
|
||||
<article className={styles.card}>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
import { Dispatch, SetStateAction, useState } from "react"
|
||||
import { type Key } from "react-aria-components"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import Select from "@/components/TempDesignSystem/Form/Select"
|
||||
|
||||
@@ -53,6 +53,7 @@ function getLevelByTier(tier: number) {
|
||||
}
|
||||
|
||||
export default function OverviewTable() {
|
||||
const intl = useIntl()
|
||||
const [selectedLevelA, setSelectedLevelA] = useState(getLevelByTier(1))
|
||||
const [selectedLevelB, setSelectedLevelB] = useState(getLevelByTier(2))
|
||||
const [selectedLevelC, setSelectedLevelC] = useState(getLevelByTier(3))
|
||||
@@ -89,8 +90,8 @@ export default function OverviewTable() {
|
||||
<div className={styles.columnHeaderContainer}>
|
||||
<div className={styles.columnHeader}>
|
||||
<Select
|
||||
name={"benefitA"}
|
||||
label={"Level"}
|
||||
name="benefitA"
|
||||
label={intl.formatMessage({ id: "Level" })}
|
||||
items={levelOptions}
|
||||
defaultSelectedKey={selectedLevelA.tier}
|
||||
onSelect={handleSelectChange(setSelectedLevelA)}
|
||||
@@ -105,8 +106,8 @@ export default function OverviewTable() {
|
||||
</div>
|
||||
<div className={styles.columnHeader}>
|
||||
<Select
|
||||
name={"benefitB"}
|
||||
label={"Level"}
|
||||
name="benefitB"
|
||||
label={intl.formatMessage({ id: "Level" })}
|
||||
items={levelOptions}
|
||||
defaultSelectedKey={selectedLevelB.tier}
|
||||
onSelect={handleSelectChange(setSelectedLevelB)}
|
||||
@@ -126,8 +127,8 @@ export default function OverviewTable() {
|
||||
<div className={styles.columnHeaderContainer}>
|
||||
<div className={styles.columnHeader}>
|
||||
<Select
|
||||
name={"benefitA"}
|
||||
label={"Level"}
|
||||
name="benefitA"
|
||||
label={intl.formatMessage({ id: "Level" })}
|
||||
items={levelOptions}
|
||||
defaultSelectedKey={selectedLevelA.tier}
|
||||
onSelect={handleSelectChange(setSelectedLevelA)}
|
||||
@@ -142,8 +143,8 @@ export default function OverviewTable() {
|
||||
</div>
|
||||
<div className={styles.columnHeader}>
|
||||
<Select
|
||||
name={"benefitB"}
|
||||
label={"Level"}
|
||||
name="benefitB"
|
||||
label={intl.formatMessage({ id: "Level" })}
|
||||
items={levelOptions}
|
||||
defaultSelectedKey={selectedLevelB.tier}
|
||||
onSelect={handleSelectChange(setSelectedLevelB)}
|
||||
@@ -158,8 +159,8 @@ export default function OverviewTable() {
|
||||
</div>
|
||||
<div className={styles.columnHeader}>
|
||||
<Select
|
||||
name={"benefitC"}
|
||||
label={"Level"}
|
||||
name="benefitC"
|
||||
label={intl.formatMessage({ id: "Level" })}
|
||||
items={levelOptions}
|
||||
defaultSelectedKey={selectedLevelC.tier}
|
||||
onSelect={handleSelectChange(setSelectedLevelC)}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import { getValueFromContactConfig } from "@/utils/contactConfig"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import ContactRow from "./ContactRow"
|
||||
|
||||
@@ -10,9 +9,10 @@ import { JoinLoyaltyContactTypenameEnum } from "@/types/components/loyalty/enums
|
||||
import type { ContactProps } from "@/types/components/loyalty/sidebar"
|
||||
|
||||
export default async function Contact({ contactBlock }: ContactProps) {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<div className={styles.contactContainer}>
|
||||
<Title level="h5">{_("Contact us")}</Title>
|
||||
<Title level="h5">{formatMessage({ id: "Contact us" })}</Title>
|
||||
<section>
|
||||
{contactBlock.map(({ contact, __typename }, i) => {
|
||||
switch (__typename) {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import Image from "@/components/Image"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import Contact from "./Contact"
|
||||
|
||||
@@ -11,7 +10,10 @@ import styles from "./joinLoyalty.module.css"
|
||||
|
||||
import type { JoinLoyaltyContactProps } from "@/types/components/loyalty/sidebar"
|
||||
|
||||
export default function JoinLoyaltyContact({ block }: JoinLoyaltyContactProps) {
|
||||
export default async function JoinLoyaltyContact({
|
||||
block,
|
||||
}: JoinLoyaltyContactProps) {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.wrapper}>
|
||||
@@ -25,12 +27,12 @@ export default function JoinLoyaltyContact({ block }: JoinLoyaltyContactProps) {
|
||||
/>
|
||||
{block.preamble && <p className={styles.preamble}>{block.preamble}</p>}
|
||||
<Button intent="primary">
|
||||
<span>{_("Join Scandic Friends")}</span>
|
||||
<span>{formatMessage({ id: "Join Scandic Friends" })}</span>
|
||||
</Button>
|
||||
<div className={styles.linkContainer}>
|
||||
<Link href="/login" className={styles.loginLink}>
|
||||
{_("Already a friend?")} <br />
|
||||
{_("Click here to log in")}
|
||||
{formatMessage({ id: "Already a friend?" })} <br />
|
||||
{formatMessage({ id: "Click here to log in" })}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,8 +8,7 @@ import Shortcuts from "@/components/MyPages/Blocks/Shortcuts"
|
||||
import PreviousStays from "@/components/MyPages/Blocks/Stays/Previous"
|
||||
import SoonestStays from "@/components/MyPages/Blocks/Stays/Soonest"
|
||||
import UpcomingStays from "@/components/MyPages/Blocks/Stays/Upcoming"
|
||||
|
||||
import { ExpiringPoints } from "../Blocks/Points/ExpiringPoints"
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
|
||||
import {
|
||||
AccountPageContentProps,
|
||||
@@ -56,7 +55,9 @@ export default function Content({ lang, content }: ContentProps) {
|
||||
href:
|
||||
item.dynamic_content.link.linkConnection.edges[0].node
|
||||
.original_url ||
|
||||
`/${lang}${item.dynamic_content.link.linkConnection.edges[0].node.url}`,
|
||||
removeMultipleSlashes(
|
||||
`/${lang}/${item.dynamic_content.link.linkConnection.edges[0].node.url}`
|
||||
),
|
||||
text: item.dynamic_content.link.link_text,
|
||||
}
|
||||
: null
|
||||
|
||||
@@ -23,19 +23,16 @@
|
||||
}
|
||||
|
||||
.card {
|
||||
flex: 1 1 0px;
|
||||
text-decoration: none;
|
||||
align-items: center;
|
||||
background-color: var(--UI-Grey-10);
|
||||
border-radius: 4px;
|
||||
color: var(--Theme-Primary-Light-On-Surface-Text);
|
||||
display: flex;
|
||||
flex: 1 1 0px;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
min-height: 280px;
|
||||
background-color: var(--UI-Grey-10);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 280px;
|
||||
padding: 30px;
|
||||
border-radius: 4px;
|
||||
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
color: var(--Theme-Primary-Light-On-Surface-Text);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import Link from "next/link"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import Header from "@/components/MyPages/Blocks/Header"
|
||||
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import levelsData from "../data"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import Link from "next/link"
|
||||
import { Lock } from "react-feather"
|
||||
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
@@ -6,6 +5,8 @@ import { serverClient } from "@/lib/trpc/server"
|
||||
import Header from "@/components/MyPages/Blocks/Header"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./next.module.css"
|
||||
|
||||
@@ -17,7 +18,7 @@ export default async function NextLevelBenefitsBlock({
|
||||
link,
|
||||
}: AccountPageComponentProps) {
|
||||
const { nextLevel, perks } = await serverClient().user.benefits.nextLevel()
|
||||
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<Header title={title} subtitle={subtitle} link={link} />
|
||||
@@ -26,7 +27,7 @@ export default async function NextLevelBenefitsBlock({
|
||||
<article key={perk.id} className={styles.card}>
|
||||
<Button type="button" disabled>
|
||||
<Lock height={16} />
|
||||
Level up to unlock
|
||||
{formatMessage({ id: "Level up to unlock" })}
|
||||
</Button>
|
||||
<div>
|
||||
<span className={styles.level}>As our {nextLevel}</span>{" "}
|
||||
@@ -36,9 +37,9 @@ export default async function NextLevelBenefitsBlock({
|
||||
))}
|
||||
</CardGrid>
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button intent="primary" asChild>
|
||||
<Link href="#" className={styles.buttonText}>
|
||||
Explore all levels and benefits
|
||||
<Button asChild intent="primary">
|
||||
<Link href="#">
|
||||
{formatMessage({ id: "Explore all levels and benefits" })}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -45,20 +45,11 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.buttonText {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
@media screen and (min-width: 950px) {
|
||||
.cardContainer {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
.level {
|
||||
font-size: var(--typography-Script-Desktop-fontSize);
|
||||
font-weight: var(--typography-Script-Desktop-fontWeight);
|
||||
}
|
||||
|
||||
.cardSubtitle {
|
||||
font-size: var(--typography-Subtitle-Desktop-fontSize, 18px);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import Image from "@/components/Image"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./challenges.module.css"
|
||||
|
||||
import type { ChallengesProps } from "@/types/components/myPages/myPage/challenges"
|
||||
|
||||
export default function Challenges({ journeys, victories }: ChallengesProps) {
|
||||
export default async function Challenges({
|
||||
journeys,
|
||||
victories,
|
||||
}: ChallengesProps) {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<section className={styles.challenges}>
|
||||
<header className={styles.header}>
|
||||
<Title level="h2">{_("Your Challenges Conquer & Earn!")}</Title>
|
||||
<Title level="h2">
|
||||
{formatMessage({ id: "Your Challenges Conquer & Earn!" })}
|
||||
</Title>
|
||||
</header>
|
||||
<section className={styles.section}>
|
||||
<header>
|
||||
<Title level="h3">{_("On your journey")}</Title>
|
||||
<Title level="h3">{formatMessage({ id: "On your journey" })}</Title>
|
||||
</header>
|
||||
<section className={styles.journeys}>
|
||||
{journeys.map((journey) => (
|
||||
@@ -28,7 +33,9 @@ export default function Challenges({ journeys, victories }: ChallengesProps) {
|
||||
</section>
|
||||
<aside className={styles.aside}>
|
||||
<header>
|
||||
<Title level="h3">{_("Previous victories")}</Title>
|
||||
<Title level="h3">
|
||||
{formatMessage({ id: "Previous victories" })}
|
||||
</Title>
|
||||
</header>
|
||||
<section className={styles.victories}>
|
||||
{victories.map((victory) => (
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function Header({
|
||||
{title}
|
||||
</Title>
|
||||
{link && (
|
||||
<Link className={styles.link} href={link.href}>
|
||||
<Link className={styles.link} href={link.href} variant="myPage">
|
||||
{link.text}
|
||||
</Link>
|
||||
)}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import Image from "@/components/Image"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
|
||||
import styles from "./btn.module.css"
|
||||
|
||||
export default function MembershipCardButton() {
|
||||
function handleShowMembershipCard() {
|
||||
console.log(`Showing membership card`)
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
className={styles.membershipBtn}
|
||||
onClick={handleShowMembershipCard}
|
||||
type="button"
|
||||
>
|
||||
<span>Membership Card</span>
|
||||
<Image alt="QR icon" height={20} src="/_static/icons/qr.svg" width={20} />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import { GoodFriend } from "@/components/Levels"
|
||||
import BiroScript from "@/components/TempDesignSystem/Text/BiroScript"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./friend.module.css"
|
||||
|
||||
import type { UserProps } from "@/types/components/myPages/user"
|
||||
|
||||
export default function Friend({ user }: UserProps) {
|
||||
export default async function Friend({ user }: UserProps) {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<section className={styles.friend}>
|
||||
<header className={styles.header}>
|
||||
<BiroScript className={styles.levelLabel} color="pale">
|
||||
Current level:
|
||||
{formatMessage({ id: "Current level" })}:
|
||||
</BiroScript>
|
||||
<GoodFriend className={styles.level} color="pale" />
|
||||
</header>
|
||||
@@ -22,7 +22,9 @@ export default function Friend({ user }: UserProps) {
|
||||
{user.name}
|
||||
</Title>
|
||||
<div className={styles.membershipContainer}>
|
||||
<p className={styles.membershipId}>{_("Membership ID:")}</p>
|
||||
<p className={styles.membershipId}>
|
||||
{formatMessage({ id: "Membership ID" })}:
|
||||
</p>
|
||||
<p className={styles.membershipId}>
|
||||
{user.membership ? user.membership.membershipNumber : "N/A"}
|
||||
</p>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import BiroScript from "@/components/TempDesignSystem/Text/BiroScript"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import Label from "../Label"
|
||||
|
||||
@@ -9,13 +8,14 @@ import styles from "./nextLevel.module.css"
|
||||
|
||||
import type { UserProps } from "@/types/components/myPages/user"
|
||||
|
||||
export default function NextLevel({}: UserProps) {
|
||||
export default async function NextLevel({}: UserProps) {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<section>
|
||||
<Label>{_("Next level")}:</Label>
|
||||
<Label>{formatMessage({ id: "Next level" })}:</Label>
|
||||
<Title className={styles.nextLevel} color="pale" level="h3">
|
||||
{_("Close friend")}
|
||||
<BiroScript>{_("Coming up")}!</BiroScript>
|
||||
N/A
|
||||
<BiroScript>{formatMessage({ id: "Coming up" })}!</BiroScript>
|
||||
</Title>
|
||||
</section>
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
@media screen and (min-width: 768px) {
|
||||
.nextLevel {
|
||||
gap: var(--Spacing-x1);
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-template-columns: auto auto;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import Label from "../Label"
|
||||
|
||||
@@ -6,17 +7,18 @@ import styles from "./totalPoints.module.css"
|
||||
|
||||
import type { UserProps } from "@/types/components/myPages/user"
|
||||
|
||||
export default function Points({ user }: UserProps) {
|
||||
export default async function Points({ user }: UserProps) {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<section className={styles.points}>
|
||||
<article>
|
||||
<Label>Total Points</Label>
|
||||
<Label>{formatMessage({ id: "Total Points" })}</Label>
|
||||
<Title color="pale" level="h2">
|
||||
{user.membership ? user.membership.currentPoints : "N/A"}
|
||||
</Title>
|
||||
</article>
|
||||
<article>
|
||||
<Label>Points until next level</Label>
|
||||
<Label>{formatMessage({ id: "Points until next level" })}</Label>
|
||||
<Title color="pale" level="h2">
|
||||
{user.membership ? user.membership.currentPoints : "N/A"}
|
||||
</Title>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import Header from "@/components/MyPages/Blocks/Header"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./currentPointsBalance.module.css"
|
||||
|
||||
@@ -14,17 +14,18 @@ async function CurrentPointsBalance({
|
||||
lang,
|
||||
}: AccountPageComponentProps) {
|
||||
const user = await serverClient().user.get()
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<div>
|
||||
<Header title={title} link={link} subtitle={subtitle} />
|
||||
|
||||
<div className={styles.card}>
|
||||
<h2>{`${_("Total points")}*`}</h2>
|
||||
<h2>{`${formatMessage({ id: "Total points" })}*`}</h2>
|
||||
<p
|
||||
className={styles.points}
|
||||
>{`${_("Points")}: ${user.membership?.currentPoints || "N/A"}`}</p>
|
||||
>{`${formatMessage({ id: "Points" })}: ${user.membership?.currentPoints || "N/A"}`}</p>
|
||||
<p className={styles.disclaimer}>
|
||||
{`*${_("Points may take up to 10 days to be displayed.")}`}
|
||||
{`*${formatMessage({ id: "Points may take up to 10 days to be displayed." })}`}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
"use client"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
import { _ } from "@/lib/translation"
|
||||
import { trpc } from "@/lib/trpc/client"
|
||||
|
||||
import Header from "@/components/MyPages/Blocks/Header"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
|
||||
import styles from "./earnAndBurn.module.css"
|
||||
|
||||
@@ -13,11 +12,11 @@ import { AccountPageComponentProps } from "@/types/components/myPages/myPage/acc
|
||||
import { Page, RowProps } from "@/types/components/myPages/myPage/earnAndBurn"
|
||||
|
||||
const tableHeadings = [
|
||||
_("Arrival date"),
|
||||
_("Description"),
|
||||
_("Booking number"),
|
||||
_("Transaction date"),
|
||||
_("Points"),
|
||||
"Arrival date",
|
||||
"Description",
|
||||
"Booking number",
|
||||
"Transaction date",
|
||||
"Points",
|
||||
]
|
||||
|
||||
function EarnAndBurn({
|
||||
@@ -26,7 +25,8 @@ function EarnAndBurn({
|
||||
subtitle,
|
||||
link,
|
||||
}: AccountPageComponentProps) {
|
||||
const { data, hasNextPage, isFetching, fetchNextPage } =
|
||||
const intl = useIntl()
|
||||
const { data, hasNextPage, fetchNextPage } =
|
||||
trpc.user.transaction.friendTransactions.useInfiniteQuery(
|
||||
{ limit: 5 },
|
||||
{
|
||||
@@ -49,8 +49,12 @@ function EarnAndBurn({
|
||||
<table className={styles.mobileTable}>
|
||||
<thead className={styles.mobileThead}>
|
||||
<tr>
|
||||
<th className={styles.mobileTh}>{_("Transactions")}</th>
|
||||
<th className={styles.mobileTh}>{_("Points")}</th>
|
||||
<th className={styles.mobileTh}>
|
||||
{intl.formatMessage({ id: "Transactions" })}
|
||||
</th>
|
||||
<th className={styles.mobileTh}>
|
||||
{intl.formatMessage({ id: "Points" })}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -72,7 +76,7 @@ function EarnAndBurn({
|
||||
<span>{`${transaction.hotelName}, ${transaction.city}`}</span>
|
||||
) : null}
|
||||
<span>
|
||||
{`${transaction.nights} ${_(transaction.nights === 1 ? "night" : "nights")}`}
|
||||
{`${transaction.nights} ${intl.formatMessage({ id: transaction.nights === 1 ? "night" : "nights" })}`}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
@@ -85,7 +89,7 @@ function EarnAndBurn({
|
||||
) : (
|
||||
<tr>
|
||||
<td className={styles.mobilePlaceholder} colSpan={2}>
|
||||
Empty
|
||||
{intl.formatMessage({ id: "Empty" })}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
@@ -99,7 +103,7 @@ function EarnAndBurn({
|
||||
<tr>
|
||||
{tableHeadings.map((heading) => (
|
||||
<th key={heading} className={styles.th}>
|
||||
{heading}
|
||||
{intl.formatMessage({ id: heading })}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
@@ -123,7 +127,7 @@ function EarnAndBurn({
|
||||
// type="button"
|
||||
// onClick={loadMoreData}
|
||||
// >
|
||||
// {_("See more transactions")}
|
||||
// {intl.formatMessage({id:"See more transactions"})}
|
||||
// </Button>
|
||||
<table className={styles.table}>
|
||||
<thead className={styles.thead}>
|
||||
@@ -141,7 +145,7 @@ function EarnAndBurn({
|
||||
colSpan={tableHeadings.length}
|
||||
className={styles.placeholder}
|
||||
>
|
||||
{_("No transactions available")}
|
||||
{intl.formatMessage({ id: "No transactions available" })}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -153,10 +157,11 @@ function EarnAndBurn({
|
||||
}
|
||||
|
||||
function Row({ transaction, lang }: RowProps) {
|
||||
const intl = useIntl()
|
||||
const description =
|
||||
transaction.hotelName && transaction.city
|
||||
? `${_(transaction.hotelName)}, ${transaction.city} ${transaction.nights} ${_("nights")}`
|
||||
: `${transaction.nights} ${_("nights")}`
|
||||
? `${intl.formatMessage({ id: transaction.hotelName })}, ${transaction.city} ${transaction.nights} ${intl.formatMessage({ id: "nights" })}`
|
||||
: `${transaction.nights} ${intl.formatMessage({ id: "nights" })}`
|
||||
const arrival = dt(transaction.checkinDate).locale(lang).format("DD MMM YYYY")
|
||||
const departure = dt(transaction.checkoutDate)
|
||||
.locale(lang)
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./expiringPoints.module.css"
|
||||
|
||||
export function ExpiringPoints() {
|
||||
export async function ExpiringPoints() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<table className={styles.table}>
|
||||
<thead className={styles.thead}>
|
||||
<tr>
|
||||
<th className={styles.th}>{_("Arrival date")}</th>
|
||||
<th className={styles.th}>{_("Points")}</th>
|
||||
<th className={styles.th}>{formatMessage({ id: "Arrival date" })}</th>
|
||||
<th className={styles.th}>{formatMessage({ id: "Points" })}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import styles from "./emptyPreviousStays.module.css"
|
||||
|
||||
export default function EmptyPreviousStaysBlock() {
|
||||
const { formatMessage } = useIntl()
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<Title as="h5" level="h3">
|
||||
{_("You have no previous stays.")}
|
||||
{formatMessage({ id: "You have no previous stays." })}
|
||||
</Title>
|
||||
</section>
|
||||
)
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
|
||||
import styles from "./button.module.css"
|
||||
@@ -8,16 +12,17 @@ export default function ShowMoreButton({
|
||||
disabled,
|
||||
loadMoreData,
|
||||
}: ShowMoreButtonParams) {
|
||||
const { formatMessage } = useIntl()
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Button
|
||||
disabled={disabled}
|
||||
intent="primary"
|
||||
theme="primaryDark"
|
||||
type="button"
|
||||
onClick={loadMoreData}
|
||||
theme="secondaryDark"
|
||||
type="button"
|
||||
>
|
||||
Show more
|
||||
{formatMessage({ id: "Show more" })}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./emptyUpcomingStays.module.css"
|
||||
|
||||
export default function EmptyUpcomingStaysBlock() {
|
||||
export default async function EmptyUpcomingStaysBlock() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<Title as="h5" level="h3">
|
||||
{_("You have no upcoming stays.")}
|
||||
{formatMessage({ id: "You have no upcoming stays." })}
|
||||
<span className={styles.grayTitle}>
|
||||
{" "}
|
||||
{_("Where should you go next?")}
|
||||
{formatMessage({ id: "Where should you go next?" })}
|
||||
</span>
|
||||
</Title>
|
||||
<Button intent="primary" asChild type="button">
|
||||
<Button asChild intent="primary" type="button">
|
||||
<Link className={styles.link} href="#" key="getInspired">
|
||||
{_("Get inspired")}
|
||||
{formatMessage({ id: "Get inspired" })}
|
||||
</Link>
|
||||
</Button>
|
||||
</section>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import MaxWidth from "@/components/MaxWidth"
|
||||
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||
|
||||
import Header from "../../Header"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
@@ -7,18 +7,19 @@ import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import styles from "./emptyUpcomingStays.module.css"
|
||||
|
||||
export default function EmptyUpcomingStaysBlock() {
|
||||
const { formatMessage } = useIntl()
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<Title as="h5" level="h3">
|
||||
{_("You have no upcoming stays.")}
|
||||
{formatMessage({ id: "You have no upcoming stays." })}
|
||||
<span className={styles.grayTitle}>
|
||||
{" "}
|
||||
{_("Where should you go next?")}
|
||||
{formatMessage({ id: "Where should you go next?" })}
|
||||
</span>
|
||||
</Title>
|
||||
<Button intent="primary" asChild type="button">
|
||||
<Button asChild intent="primary" type="button">
|
||||
<Link className={styles.link} href="#" key="getInspired">
|
||||
{_("Get inspired")}
|
||||
{formatMessage({ id: "Get inspired" })}
|
||||
</Link>
|
||||
</Button>
|
||||
</section>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"use client"
|
||||
|
||||
import { _ } from "@/lib/translation"
|
||||
import { trpc } from "@/lib/trpc/client"
|
||||
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { _ } from "@/lib/translation"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import Breadcrumb from "./Breadcrumb"
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
.user {
|
||||
align-items: center;
|
||||
background-color: var(--some-black-color, #000);
|
||||
border-radius: 50%;
|
||||
color: var(--some-white-color, #fff);
|
||||
display: flex;
|
||||
font-family: var(--typography-Body-Regular-fontFamily);
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
height: 3.5rem;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: 3.5rem;
|
||||
}
|
||||
|
||||
.alert {
|
||||
align-items: center;
|
||||
background-color: var(--some-red-color, #ed2027);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
font-size: 1rem;
|
||||
height: 2rem;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: -1rem;
|
||||
top: -0.5rem;
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.user {
|
||||
height: 2.8rem;
|
||||
width: 2.8rem;
|
||||
}
|
||||
|
||||
.alert {
|
||||
font-size: 0.6rem;
|
||||
height: 1rem;
|
||||
right: -0.2rem;
|
||||
top: -0.1rem;
|
||||
width: 1rem;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./sidebar.module.css"
|
||||
|
||||
@@ -13,6 +14,7 @@ import { LangParams } from "@/types/params"
|
||||
|
||||
export default async function Sidebar({ lang }: LangParams) {
|
||||
const navigation = await serverClient().contentstack.myPages.navigation.get()
|
||||
const { formatMessage } = await getIntl()
|
||||
|
||||
return (
|
||||
<aside className={styles.sidebar}>
|
||||
@@ -29,21 +31,21 @@ export default async function Sidebar({ lang }: LangParams) {
|
||||
</Link>
|
||||
{item.subItems
|
||||
? item.subItems.map((subItem) => (
|
||||
<Link
|
||||
key={subItem.uid}
|
||||
href={subItem.originalUrl || subItem.url}
|
||||
partialMatch
|
||||
variant="sidebar"
|
||||
>
|
||||
{subItem.linkText}
|
||||
</Link>
|
||||
))
|
||||
<Link
|
||||
key={subItem.uid}
|
||||
href={subItem.originalUrl || subItem.url}
|
||||
partialMatch
|
||||
variant="sidebar"
|
||||
>
|
||||
{subItem.linkText}
|
||||
</Link>
|
||||
))
|
||||
: null}
|
||||
</Fragment>
|
||||
))}
|
||||
|
||||
<Link prefetch={false} href={logout[lang]} variant="sidebar">
|
||||
Log out <LogOut height={16} width={16} />
|
||||
{formatMessage({ id: "Log out" })} <LogOut height={16} width={16} />
|
||||
</Link>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import Card from "@/components/MyProfile/Card"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./com.module.css"
|
||||
|
||||
export default function CommunicationPreferences() {
|
||||
export default async function CommunicationPreferences() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<Title level="h2">My communication preferences</Title>
|
||||
<Title level="h4">
|
||||
{formatMessage({ id: "My communication preferences" })}
|
||||
</Title>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import Card from "@/components/MyProfile/Card"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./creditCards.module.css"
|
||||
|
||||
export default function CreditCards() {
|
||||
export default async function CreditCards() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<Title level="h2">My credit cards</Title>
|
||||
<Title level="h4">{formatMessage({ id: "My credit cards" })}</Title>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import Card from "@/components/MyProfile/Card"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./membershipCard.module.css"
|
||||
|
||||
export default function MembershipCard() {
|
||||
export default async function MembershipCard() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<Title level="h2">Membership cards</Title>
|
||||
<Title level="h4">{formatMessage({ id: "Membership cards" })}</Title>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import Card from "@/components/MyProfile/Card"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./password.module.css"
|
||||
|
||||
export default function Password() {
|
||||
export default async function Password() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<Title level="h2">Password</Title>
|
||||
<Title level="h4">{formatMessage({ id: "Password" })}</Title>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import { useEffect } from "react"
|
||||
import { useFormStatus } from "react-dom"
|
||||
import { useWatch } from "react-hook-form"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { _ } from "@/lib/translation"
|
||||
import { useProfileStore } from "@/stores/edit-profile"
|
||||
|
||||
import {
|
||||
@@ -21,6 +21,7 @@ import Phone from "@/components/TempDesignSystem/Form/Phone"
|
||||
import type { EditFormContentProps } from "@/types/components/myPages/myProfile/edit"
|
||||
|
||||
export default function FormContent({ control }: EditFormContentProps) {
|
||||
const { formatMessage } = useIntl()
|
||||
const { pending } = useFormStatus()
|
||||
const setIsPending = useProfileStore((store) => store.setIsPending)
|
||||
const country = useWatch({ name: "address.country" })
|
||||
@@ -29,11 +30,18 @@ export default function FormContent({ control }: EditFormContentProps) {
|
||||
setIsPending(pending)
|
||||
}, [pending, setIsPending])
|
||||
|
||||
const city = formatMessage({ id: "City" })
|
||||
const email = formatMessage({ id: "Email" })
|
||||
const street = formatMessage({ id: "Street" })
|
||||
const zipCode = formatMessage({ id: "Zip code" })
|
||||
|
||||
return (
|
||||
<>
|
||||
<Field>
|
||||
<Field.Icon>{country}</Field.Icon>
|
||||
<Field.Label htmlFor="address.country">*{_("Country")}</Field.Label>
|
||||
<Field.Label htmlFor="address.country">
|
||||
*{formatMessage({ id: "Country" })}
|
||||
</Field.Label>
|
||||
<Field.Content>
|
||||
<CountrySelect name="address.country" />
|
||||
</Field.Content>
|
||||
@@ -43,7 +51,9 @@ export default function FormContent({ control }: EditFormContentProps) {
|
||||
<Field.Icon>
|
||||
<CalendarIcon />
|
||||
</Field.Icon>
|
||||
<Field.Label htmlFor="dateOfBirth">*{_("Date of Birth")}</Field.Label>
|
||||
<Field.Label htmlFor="dateOfBirth">
|
||||
*{formatMessage({ id: "Date of Birth" })}
|
||||
</Field.Label>
|
||||
<Field.Content>
|
||||
<DateSelect
|
||||
control={control}
|
||||
@@ -57,13 +67,13 @@ export default function FormContent({ control }: EditFormContentProps) {
|
||||
<Field.Icon>
|
||||
<EmailIcon />
|
||||
</Field.Icon>
|
||||
<Field.Label htmlFor="email">*{_("Email")}</Field.Label>
|
||||
<Field.Label htmlFor="email">*{email}</Field.Label>
|
||||
<Field.Content>
|
||||
<Input
|
||||
aria-label={_("Email")}
|
||||
aria-label={email}
|
||||
control={control}
|
||||
name="email"
|
||||
placeholder={_("Email")}
|
||||
placeholder={email}
|
||||
registerOptions={{ required: true }}
|
||||
type="email"
|
||||
/>
|
||||
@@ -74,7 +84,9 @@ export default function FormContent({ control }: EditFormContentProps) {
|
||||
<Field.Icon>
|
||||
<PhoneIcon />
|
||||
</Field.Icon>
|
||||
<Field.Label htmlFor="phoneNumber">*{_("Phone")}</Field.Label>
|
||||
<Field.Label htmlFor="phoneNumber">
|
||||
*{formatMessage({ id: "Phone" })}
|
||||
</Field.Label>
|
||||
<Field.Content>
|
||||
<Phone countrySelectName="address.country" name="phoneNumber" />
|
||||
</Field.Content>
|
||||
@@ -85,14 +97,14 @@ export default function FormContent({ control }: EditFormContentProps) {
|
||||
<HouseIcon />
|
||||
</Field.Icon>
|
||||
<Field.Label htmlFor="address.streetAddress">
|
||||
{_("Address")}
|
||||
{formatMessage({ id: "Address" })}
|
||||
</Field.Label>
|
||||
<Field.Content>
|
||||
<Input
|
||||
aria-label={_("Street")}
|
||||
aria-label={street}
|
||||
control={control}
|
||||
name="address.streetAddress"
|
||||
placeholder={_("Street 123")}
|
||||
placeholder={street}
|
||||
/>
|
||||
</Field.Content>
|
||||
</Field>
|
||||
@@ -101,13 +113,15 @@ export default function FormContent({ control }: EditFormContentProps) {
|
||||
<Field.Icon>
|
||||
<HouseIcon />
|
||||
</Field.Icon>
|
||||
<Field.Label htmlFor="address.city">{_("City/State")}</Field.Label>
|
||||
<Field.Label htmlFor="address.city">
|
||||
{formatMessage({ id: "City/State" })}
|
||||
</Field.Label>
|
||||
<Field.Content>
|
||||
<Input
|
||||
aria-label={_("City")}
|
||||
aria-label={city}
|
||||
control={control}
|
||||
name="address.city"
|
||||
placeholder={_("City")}
|
||||
placeholder={city}
|
||||
/>
|
||||
</Field.Content>
|
||||
</Field>
|
||||
@@ -116,13 +130,13 @@ export default function FormContent({ control }: EditFormContentProps) {
|
||||
<Field.Icon>
|
||||
<HouseIcon />
|
||||
</Field.Icon>
|
||||
<Field.Label htmlFor="address.zipCode">*{_("Zip code")}</Field.Label>
|
||||
<Field.Label htmlFor="address.zipCode">*{zipCode}</Field.Label>
|
||||
<Field.Content>
|
||||
<Input
|
||||
aria-label={_("Zip code")}
|
||||
aria-label={zipCode}
|
||||
control={control}
|
||||
name="address.zipCode"
|
||||
placeholder={_("Zip code")}
|
||||
placeholder={zipCode}
|
||||
registerOptions={{ required: true }}
|
||||
/>
|
||||
</Field.Content>
|
||||
|
||||
@@ -1,25 +1,17 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import { phoneValidator } from "@/utils/phoneValidator"
|
||||
|
||||
export const editProfileSchema = z.object({
|
||||
"address.country": z
|
||||
.string({ required_error: _("Country is required") })
|
||||
.min(1, { message: _("Country is required") }),
|
||||
"address.country": z.string().min(1),
|
||||
"address.city": z.string().optional(),
|
||||
"address.streetAddress": z.string().optional(),
|
||||
"address.zipCode": z
|
||||
.string({ required_error: _("Zip code is required") })
|
||||
.min(1, { message: _("Zip code is required") }),
|
||||
dateOfBirth: z
|
||||
.string({ required_error: _("Date of Birth is required") })
|
||||
.min(1, { message: _("Date of Birth is required") }),
|
||||
"address.zipCode": z.string().min(1),
|
||||
dateOfBirth: z.string().min(1),
|
||||
email: z.string().email(),
|
||||
phoneNumber: phoneValidator(
|
||||
_("Phone is required"),
|
||||
_("Please enter a valid phone number")
|
||||
"Phone is required",
|
||||
"Please enter a valid phone number"
|
||||
),
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { dt } from "@/lib/dt"
|
||||
import { _ } from "@/lib/translation"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import {
|
||||
@@ -9,6 +8,7 @@ import {
|
||||
PhoneIcon,
|
||||
} from "@/components/Icons"
|
||||
import { countries } from "@/components/TempDesignSystem/Form/Country/countries"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import Field from "../Field"
|
||||
import Container from "./Container"
|
||||
@@ -16,6 +16,7 @@ import Container from "./Container"
|
||||
import styles from "./profile.module.css"
|
||||
|
||||
export default async function Profile() {
|
||||
const { formatMessage } = await getIntl()
|
||||
const user = await serverClient().user.get()
|
||||
const countryName = countries.find(
|
||||
(country) => country.code === user.address.country
|
||||
@@ -26,49 +27,55 @@ export default async function Profile() {
|
||||
<section className={styles.info}>
|
||||
<Field>
|
||||
<Field.Icon>{user.address.country}</Field.Icon>
|
||||
<Field.TextLabel>{_("Country")}</Field.TextLabel>
|
||||
<Field.TextLabel>{formatMessage({ id: "Country" })}</Field.TextLabel>
|
||||
<Field.Content>{countryName?.name}</Field.Content>
|
||||
</Field>
|
||||
<Field>
|
||||
<Field.Icon>
|
||||
<CalendarIcon />
|
||||
</Field.Icon>
|
||||
<Field.TextLabel>{_("Date of Birth")}</Field.TextLabel>
|
||||
<Field.TextLabel>
|
||||
{formatMessage({ id: "Date of Birth" })}
|
||||
</Field.TextLabel>
|
||||
<Field.Content>{dob}</Field.Content>
|
||||
</Field>
|
||||
<Field>
|
||||
<Field.Icon>
|
||||
<EmailIcon />
|
||||
</Field.Icon>
|
||||
<Field.TextLabel>{_("Email")}</Field.TextLabel>
|
||||
<Field.TextLabel>{formatMessage({ id: "Email" })}</Field.TextLabel>
|
||||
<Field.Content>{user.email}</Field.Content>
|
||||
</Field>
|
||||
<Field>
|
||||
<Field.Icon>
|
||||
<PhoneIcon />
|
||||
</Field.Icon>
|
||||
<Field.TextLabel>{_("Phone number")}</Field.TextLabel>
|
||||
<Field.TextLabel>
|
||||
{formatMessage({ id: "Phone number" })}
|
||||
</Field.TextLabel>
|
||||
<Field.Content>{user.phoneNumber}</Field.Content>
|
||||
</Field>
|
||||
<Field>
|
||||
<Field.Icon>
|
||||
<HouseIcon />
|
||||
</Field.Icon>
|
||||
<Field.TextLabel>{_("Address")}</Field.TextLabel>
|
||||
<Field.TextLabel>{formatMessage({ id: "Address" })}</Field.TextLabel>
|
||||
<Field.Content>{user.address.streetAddress || "-"}</Field.Content>
|
||||
</Field>
|
||||
<Field>
|
||||
<Field.Icon>
|
||||
<HouseIcon />
|
||||
</Field.Icon>
|
||||
<Field.TextLabel>{_("City/State")}</Field.TextLabel>
|
||||
<Field.TextLabel>
|
||||
{formatMessage({ id: "City/State" })}
|
||||
</Field.TextLabel>
|
||||
<Field.Content>{user.address.city || "-"}</Field.Content>
|
||||
</Field>
|
||||
<Field>
|
||||
<Field.Icon>
|
||||
<HouseIcon />
|
||||
</Field.Icon>
|
||||
<Field.TextLabel>{_("Zip code")}</Field.TextLabel>
|
||||
<Field.TextLabel>{formatMessage({ id: "Zip code" })}</Field.TextLabel>
|
||||
<Field.Content>{user.address.zipCode}</Field.Content>
|
||||
</Field>
|
||||
</section>
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import Card from "@/components/MyProfile/Card"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./wishes.module.css"
|
||||
|
||||
export default function Wishes() {
|
||||
export default async function Wishes() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Card className={styles.container}>
|
||||
<Title level="h2">My wishes</Title>
|
||||
<Title level="h4">{formatMessage({ id: "My wishes" })}</Title>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,30 +1,11 @@
|
||||
import { Lang } from "@/constants/languages"
|
||||
|
||||
export default function SkipToMainContent({ lang }: { lang: Lang }) {
|
||||
let message = "Skip to main content"
|
||||
|
||||
switch (lang) {
|
||||
case Lang.de:
|
||||
message = "Direkt zum Inhalt"
|
||||
break
|
||||
case Lang.sv:
|
||||
message = "Fortsätt till huvudinnehåll"
|
||||
break
|
||||
case Lang.da:
|
||||
message = "Spring over og gå til hovedindhold"
|
||||
break
|
||||
case Lang.no:
|
||||
message = "Gå videre til hovedsiden"
|
||||
break
|
||||
case Lang.fi:
|
||||
message = "Siirry pääsisältöön"
|
||||
break
|
||||
}
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
export default async function SkipToMainContent() {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<div className="navigation--skip-to-content">
|
||||
<a data-js="skip-to-content" href="#maincontent">
|
||||
{message}
|
||||
{formatMessage({ id: "Skip to main content" })}
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -2,6 +2,5 @@ import type { RegisterOptions } from "react-hook-form"
|
||||
|
||||
export type CountryProps = {
|
||||
name?: string
|
||||
placeholder?: string
|
||||
registerOptions?: RegisterOptions
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ import {
|
||||
Popover,
|
||||
} from "react-aria-components"
|
||||
import { useController, useFormContext } from "react-hook-form"
|
||||
|
||||
import { _ } from "@/lib/translation"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import SelectChevron from "../SelectChevron"
|
||||
import { countries } from "./countries"
|
||||
@@ -24,9 +23,9 @@ import type { CountryProps } from "./country"
|
||||
|
||||
export default function CountrySelect({
|
||||
name = "country",
|
||||
placeholder = "Select a country",
|
||||
registerOptions,
|
||||
}: CountryProps) {
|
||||
const { formatMessage } = useIntl()
|
||||
const divRef = useRef<HTMLDivElement>(null)
|
||||
const { control, setValue } = useFormContext()
|
||||
const { field } = useController({
|
||||
@@ -39,10 +38,12 @@ export default function CountrySelect({
|
||||
setValue(name, country)
|
||||
}
|
||||
|
||||
const selectCountryLabel = formatMessage({ id: "Select a country" })
|
||||
|
||||
return (
|
||||
<div className={styles.container} ref={divRef}>
|
||||
<ComboBox
|
||||
aria-label={_("Select country of residence")}
|
||||
aria-label={formatMessage({ id: "Select country of residence" })}
|
||||
className={styles.select}
|
||||
isRequired={!!registerOptions?.required}
|
||||
name={field.name}
|
||||
@@ -53,9 +54,9 @@ export default function CountrySelect({
|
||||
>
|
||||
<div className={styles.comboBoxContainer}>
|
||||
<Input
|
||||
aria-label="Selected country"
|
||||
aria-label={selectCountryLabel}
|
||||
className={styles.input}
|
||||
placeholder={_(placeholder)}
|
||||
placeholder={selectCountryLabel}
|
||||
/>
|
||||
<Button className={styles.button}>
|
||||
<SelectChevron />
|
||||
|
||||
@@ -7,9 +7,9 @@ import {
|
||||
Group,
|
||||
} from "react-aria-components"
|
||||
import { useController, useFormContext, useWatch } from "react-hook-form"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import { rangeArray } from "@/utils/rangeArray"
|
||||
|
||||
@@ -28,6 +28,7 @@ export default function DateSelect({
|
||||
name,
|
||||
registerOptions,
|
||||
}: DateProps) {
|
||||
const { formatMessage } = useIntl()
|
||||
const d = useWatch({ name })
|
||||
const { setValue } = useFormContext()
|
||||
const { field } = useController({
|
||||
@@ -58,9 +59,13 @@ export default function DateSelect({
|
||||
}
|
||||
}
|
||||
|
||||
const dayLabel = formatMessage({ id: "Day" })
|
||||
const monthLabel = formatMessage({ id: "Month" })
|
||||
const yearLabel = formatMessage({ id: "Year" })
|
||||
|
||||
return (
|
||||
<DatePicker
|
||||
aria-label="Select date of birth"
|
||||
aria-label={formatMessage({ id: "Select date of birth" })}
|
||||
granularity="day"
|
||||
isRequired={!!registerOptions.required}
|
||||
name={name}
|
||||
@@ -85,12 +90,12 @@ export default function DateSelect({
|
||||
return (
|
||||
<DateSegment className={styles.day} segment={segment}>
|
||||
<Select
|
||||
aria-label={_("Day")}
|
||||
aria-label={dayLabel}
|
||||
items={days}
|
||||
label={_("Day")}
|
||||
label={dayLabel}
|
||||
name={DateName.date}
|
||||
onSelect={createOnSelect(DateName.date)}
|
||||
placeholder={_("DD")}
|
||||
placeholder="DD"
|
||||
value={segment.value}
|
||||
/>
|
||||
</DateSegment>
|
||||
@@ -99,12 +104,12 @@ export default function DateSelect({
|
||||
return (
|
||||
<DateSegment className={styles.month} segment={segment}>
|
||||
<Select
|
||||
aria-label={_("Month")}
|
||||
aria-label={monthLabel}
|
||||
items={months}
|
||||
label={_("Month")}
|
||||
label={monthLabel}
|
||||
name={DateName.month}
|
||||
onSelect={createOnSelect(DateName.month)}
|
||||
placeholder={_("MM")}
|
||||
placeholder="MM"
|
||||
value={segment.value}
|
||||
/>
|
||||
</DateSegment>
|
||||
@@ -113,12 +118,12 @@ export default function DateSelect({
|
||||
return (
|
||||
<DateSegment className={styles.year} segment={segment}>
|
||||
<Select
|
||||
aria-label={_("Year")}
|
||||
aria-label={yearLabel}
|
||||
items={years}
|
||||
label={_("Year")}
|
||||
label={yearLabel}
|
||||
name={DateName.year}
|
||||
onSelect={createOnSelect(DateName.year)}
|
||||
placeholder={_("YYYY")}
|
||||
placeholder="YYYY"
|
||||
value={segment.value}
|
||||
/>
|
||||
</DateSegment>
|
||||
|
||||
@@ -6,6 +6,16 @@
|
||||
font-family: var(--typography-Body-Regular-fontFamily);
|
||||
}
|
||||
|
||||
.myPage {
|
||||
color: var(--some-black-color, #000);
|
||||
font-family: var(--ff-fira-sans);
|
||||
font-size: 1.6rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.6%;
|
||||
line-height: 2.4rem;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
align-items: center;
|
||||
color: var(--some-text-color, #111);
|
||||
|
||||
@@ -10,6 +10,7 @@ export const linkVariants = cva(styles.link, {
|
||||
size: {},
|
||||
variant: {
|
||||
default: styles.default,
|
||||
myPage: styles.myPage,
|
||||
sidebar: styles.sidebar,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import { ArrowLeft } from "react-feather"
|
||||
|
||||
import { overview } from "@/constants/routes/webviews"
|
||||
import { _ } from "@/lib/translation"
|
||||
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./linkToOverview.module.css"
|
||||
|
||||
import { LangParams } from "@/types/params"
|
||||
import type { LangParams } from "@/types/params"
|
||||
|
||||
export default function LinkToOverview({ lang }: LangParams) {
|
||||
export default async function LinkToOverview({ lang }: LangParams) {
|
||||
const { formatMessage } = await getIntl()
|
||||
return (
|
||||
<Link className={styles.overviewLink} href={overview[lang]}>
|
||||
<ArrowLeft height={20} width={20} /> {_("Go back to overview")}
|
||||
<ArrowLeft height={20} width={20} />{" "}
|
||||
{formatMessage({ id: "Go back to overview" })}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user