feat(SW-706): make eslint rule 'formatjs/no-literal-string-in-jsx' pass
This commit is contained in:
@@ -12,7 +12,11 @@ export default async function HowItWorks({ dynamic_content }: HowItWorksProps) {
|
||||
return (
|
||||
<SectionWrapper dynamic_content={dynamic_content}>
|
||||
<section className={styles.container}>
|
||||
<Title level="h3">{intl.formatMessage({ id: "How it works" })}</Title>
|
||||
<Title level="h3">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "How it works",
|
||||
})}
|
||||
</Title>
|
||||
</section>
|
||||
</SectionWrapper>
|
||||
)
|
||||
|
||||
@@ -33,8 +33,12 @@ export default function Filter({
|
||||
<Select
|
||||
items={countryFilters}
|
||||
defaultSelectedKey={""}
|
||||
label={intl.formatMessage({ id: "Country" })}
|
||||
aria-label={intl.formatMessage({ id: "Country" })}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Country",
|
||||
})}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Country",
|
||||
})}
|
||||
name="country"
|
||||
onSelect={(value) => onFilterChange(JobylonFilterKey.country, value)}
|
||||
/>
|
||||
@@ -42,10 +46,10 @@ export default function Filter({
|
||||
items={cityFilters}
|
||||
defaultSelectedKey={""}
|
||||
label={intl.formatMessage({
|
||||
id: "Location (shown in local language)",
|
||||
defaultMessage: "Location (shown in local language)",
|
||||
})}
|
||||
aria-label={intl.formatMessage({
|
||||
id: "Location (shown in local language)",
|
||||
defaultMessage: "Location (shown in local language)",
|
||||
})}
|
||||
name="city"
|
||||
onSelect={(value) => onFilterChange(JobylonFilterKey.city, value)}
|
||||
@@ -53,16 +57,24 @@ export default function Filter({
|
||||
<Select
|
||||
items={departmentFilters}
|
||||
defaultSelectedKey={""}
|
||||
label={intl.formatMessage({ id: "Hotel or office" })}
|
||||
aria-label={intl.formatMessage({ id: "Hotel or office" })}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Hotel or office",
|
||||
})}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Hotel or office",
|
||||
})}
|
||||
name="department"
|
||||
onSelect={(value) => onFilterChange(JobylonFilterKey.department, value)}
|
||||
/>
|
||||
<Select
|
||||
items={categoryFilters}
|
||||
defaultSelectedKey={""}
|
||||
label={intl.formatMessage({ id: "Category" })}
|
||||
aria-label={intl.formatMessage({ id: "Category" })}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Category",
|
||||
})}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Category",
|
||||
})}
|
||||
name="category"
|
||||
onSelect={(value) => onFilterChange(JobylonFilterKey.category, value)}
|
||||
/>
|
||||
|
||||
@@ -31,19 +31,39 @@ export default function JobList({ allJobs }: JobListProps) {
|
||||
}
|
||||
|
||||
const countryFilters = [
|
||||
{ label: intl.formatMessage({ id: "All countries" }), value: "" },
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "All countries",
|
||||
}),
|
||||
value: "",
|
||||
},
|
||||
...state.countryFilters,
|
||||
]
|
||||
const cityFilters = [
|
||||
{ label: intl.formatMessage({ id: "All locations" }), value: "" },
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "All locations",
|
||||
}),
|
||||
value: "",
|
||||
},
|
||||
...state.cityFilters,
|
||||
]
|
||||
const departmentFilters = [
|
||||
{ label: intl.formatMessage({ id: "All hotels and offices" }), value: "" },
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "All hotels and offices",
|
||||
}),
|
||||
value: "",
|
||||
},
|
||||
...state.departmentFilters,
|
||||
]
|
||||
const categoryFilters = [
|
||||
{ label: intl.formatMessage({ id: "All categories" }), value: "" },
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "All categories",
|
||||
}),
|
||||
value: "",
|
||||
},
|
||||
...state.categoryFilters,
|
||||
]
|
||||
|
||||
@@ -59,7 +79,7 @@ export default function JobList({ allJobs }: JobListProps) {
|
||||
<Subtitle type="two">
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "{count, plural, one {# Result} other {# Results}}",
|
||||
defaultMessage: "{count, plural, one {# Result} other {# Results}}",
|
||||
},
|
||||
{ count: state.jobs.length }
|
||||
)}
|
||||
|
||||
@@ -24,10 +24,14 @@ export default function JobylonCard({ job }: JobylonCardProps) {
|
||||
const lang = useLang()
|
||||
const deadlineText = job.toDate
|
||||
? intl.formatMessage(
|
||||
{ id: "Deadline: {date}" },
|
||||
{
|
||||
defaultMessage: "Deadline: {date}",
|
||||
},
|
||||
{ date: dt(job.toDate).locale(lang).format("Do MMMM") }
|
||||
)
|
||||
: intl.formatMessage({ id: "Open for application" })
|
||||
: intl.formatMessage({
|
||||
defaultMessage: "Open for application",
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={styles.jobylonCard}>
|
||||
@@ -53,7 +57,9 @@ export default function JobylonCard({ job }: JobylonCardProps) {
|
||||
asChild
|
||||
>
|
||||
<a href={job.url} target="_blank" rel="noopener noreferrer">
|
||||
{intl.formatMessage({ id: "View & apply" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "View & apply",
|
||||
})}
|
||||
<MaterialIcon icon="open_in_new" size={20} />
|
||||
</a>
|
||||
</Button>
|
||||
|
||||
@@ -37,14 +37,17 @@ async function LevelCard({ level }: LevelCardProps) {
|
||||
const intl = await getIntl()
|
||||
|
||||
let pointsMsg: React.ReactNode = intl.formatMessage(
|
||||
{ id: "{pointsAmount, number} points" },
|
||||
{
|
||||
defaultMessage: "{pointsAmount, number} points",
|
||||
},
|
||||
{ pointsAmount: level.required_points }
|
||||
)
|
||||
|
||||
if (level.required_nights) {
|
||||
pointsMsg = intl.formatMessage(
|
||||
{
|
||||
id: "{pointsAmount, number} points <highlight>or {nightsAmount, number} nights</highlight>",
|
||||
defaultMessage:
|
||||
"{pointsAmount, number} points <highlight>or {nightsAmount, number} nights</highlight>",
|
||||
},
|
||||
{
|
||||
pointsAmount: level.required_points,
|
||||
@@ -63,7 +66,9 @@ async function LevelCard({ level }: LevelCardProps) {
|
||||
tilted="large"
|
||||
>
|
||||
{intl.formatMessage(
|
||||
{ id: "Level {level}" },
|
||||
{
|
||||
defaultMessage: "Level {level}",
|
||||
},
|
||||
{ level: level.user_facing_tag }
|
||||
)}
|
||||
</BiroScript>
|
||||
|
||||
@@ -18,10 +18,16 @@ export default function CopyButton({ membershipNumber }: CopyButtonProps) {
|
||||
try {
|
||||
navigator.clipboard.writeText(membershipNumber)
|
||||
toast.success(
|
||||
intl.formatMessage({ id: "Membership ID copied to clipboard" })
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Membership ID copied to clipboard",
|
||||
})
|
||||
)
|
||||
} catch {
|
||||
toast.error(intl.formatMessage({ id: "Failed to copy" }))
|
||||
toast.error(
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Failed to copy",
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,17 @@ export default async function MembershipNumber({
|
||||
return (
|
||||
<div className={classNames}>
|
||||
<Caption color="pale">
|
||||
{intl.formatMessage({ id: "Membership ID:" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Membership ID:",
|
||||
})}
|
||||
</Caption>
|
||||
<span className={styles.icon}>
|
||||
<Caption className={styles.icon} color="pale" asChild>
|
||||
<code data-hj-suppress>
|
||||
{membership?.membershipNumber ?? intl.formatMessage({ id: "N/A" })}
|
||||
{membership?.membershipNumber ??
|
||||
intl.formatMessage({
|
||||
defaultMessage: "N/A",
|
||||
})}
|
||||
</code>
|
||||
</Caption>
|
||||
{membership?.membershipNumber && (
|
||||
|
||||
@@ -24,10 +24,14 @@ export default async function Friend({
|
||||
}
|
||||
const isHighestLevel = isHighestMembership(membership.membershipLevel)
|
||||
|
||||
const lvlMessageHighest = intl.formatMessage({ id: "Highest level" })
|
||||
const lvlMessageHighest = intl.formatMessage({
|
||||
defaultMessage: "Highest level",
|
||||
})
|
||||
|
||||
const lvlMessageLevel = intl.formatMessage(
|
||||
{ id: "Level {level}" },
|
||||
{
|
||||
defaultMessage: "Level {level}",
|
||||
},
|
||||
{ level: membershipLevels[membership.membershipLevel] }
|
||||
)
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ export default async function ExpiringPoints({ user }: UserProps) {
|
||||
<section>
|
||||
<Body color="white" textTransform="bold" textAlign="center">
|
||||
{intl.formatMessage(
|
||||
{ id: "{points} spendable points expiring by {date}" },
|
||||
{
|
||||
defaultMessage: "{points} spendable points expiring by {date}",
|
||||
},
|
||||
{
|
||||
points: intl.formatNumber(membership.pointsToExpire),
|
||||
date: d.format(dateFormat),
|
||||
|
||||
@@ -25,15 +25,23 @@ export default async function Points({ user }: UserProps) {
|
||||
<PointsContainer>
|
||||
<PointsColumn
|
||||
value={membership?.currentPoints}
|
||||
title={intl.formatMessage({ id: "Your points to spend" })}
|
||||
subtitle={intl.formatMessage({ id: "as of today" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Your points to spend",
|
||||
})}
|
||||
subtitle={intl.formatMessage({
|
||||
defaultMessage: "as of today",
|
||||
})}
|
||||
/>
|
||||
{nextLevel && (
|
||||
<PointsColumn
|
||||
value={membership?.pointsRequiredToNextlevel}
|
||||
title={intl.formatMessage({ id: "Points needed to level up" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Points needed to level up",
|
||||
})}
|
||||
subtitle={intl.formatMessage(
|
||||
{ id: "next level: {nextLevel}" },
|
||||
{
|
||||
defaultMessage: "next level: {nextLevel}",
|
||||
},
|
||||
{ nextLevel: nextLevel.name }
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -99,9 +99,13 @@ export default function OverviewTableClient({
|
||||
showDescription={false}
|
||||
/>
|
||||
<Select
|
||||
aria-label={intl.formatMessage({ id: "Level" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Level",
|
||||
})}
|
||||
name={`reward` + column}
|
||||
label={intl.formatMessage({ id: "Level" })}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Level",
|
||||
})}
|
||||
items={levelOptions}
|
||||
value={selectedLevelMobile.level_id}
|
||||
onSelect={handleSelectChange(actionEnumMobile)}
|
||||
@@ -134,9 +138,13 @@ export default function OverviewTableClient({
|
||||
}
|
||||
return (
|
||||
<Select
|
||||
aria-label={intl.formatMessage({ id: "Level" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Level",
|
||||
})}
|
||||
name={`reward` + column}
|
||||
label={intl.formatMessage({ id: "Level" })}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Level",
|
||||
})}
|
||||
items={levelOptions}
|
||||
value={selectedLevelDesktop.level_id}
|
||||
onSelect={handleSelectChange(actionEnumDesktop)}
|
||||
|
||||
@@ -13,7 +13,8 @@ export default function LevelSummary({
|
||||
const pointsMsg: React.ReactNode = level.required_nights
|
||||
? intl.formatMessage(
|
||||
{
|
||||
id: "{pointsAmount, number} points or {nightsAmount, number} nights",
|
||||
defaultMessage:
|
||||
"{pointsAmount, number} points or {nightsAmount, number} nights",
|
||||
},
|
||||
{
|
||||
pointsAmount: level.required_points,
|
||||
@@ -21,7 +22,9 @@ export default function LevelSummary({
|
||||
}
|
||||
)
|
||||
: intl.formatMessage(
|
||||
{ id: "{pointsAmount, number} points" },
|
||||
{
|
||||
defaultMessage: "{pointsAmount, number} points",
|
||||
},
|
||||
{ pointsAmount: level.required_points }
|
||||
)
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@ export default function YourLevel() {
|
||||
type="two"
|
||||
textAlign={"center"}
|
||||
>
|
||||
{intl.formatMessage({ id: "Your level" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Your level",
|
||||
})}
|
||||
</BiroScript>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@ export default function AwardPoints({
|
||||
<Body textTransform="bold" className={classNames}>
|
||||
{isCalculated
|
||||
? intl.formatNumber(awardPoints)
|
||||
: intl.formatMessage({ id: "Points being calculated" })}
|
||||
: intl.formatMessage({
|
||||
defaultMessage: "Points being calculated",
|
||||
})}
|
||||
</Body>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function Row({ transaction }: RowProps) {
|
||||
|
||||
const nightsMsg = intl.formatMessage(
|
||||
{
|
||||
id: "{totalNights, plural, one {# night} other {# nights}}",
|
||||
defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
|
||||
},
|
||||
{
|
||||
totalNights: transaction.nights,
|
||||
@@ -40,28 +40,40 @@ export default function Row({ transaction }: RowProps) {
|
||||
case Transactions.rewardType.stay:
|
||||
case Transactions.rewardType.stayAdj:
|
||||
if (transaction.hotelId === "ORS") {
|
||||
description = intl.formatMessage({ id: "Former Scandic Hotel" })
|
||||
description = intl.formatMessage({
|
||||
defaultMessage: "Former Scandic Hotel",
|
||||
})
|
||||
}
|
||||
if (transaction.confirmationNumber === "BALFWD") {
|
||||
description = intl.formatMessage({
|
||||
id: "Points earned prior to May 1, 2021",
|
||||
defaultMessage: "Points earned prior to May 1, 2021",
|
||||
})
|
||||
}
|
||||
break
|
||||
case Transactions.rewardType.ancillary:
|
||||
description = intl.formatMessage({ id: "Extras to your booking" })
|
||||
description = intl.formatMessage({
|
||||
defaultMessage: "Extras to your booking",
|
||||
})
|
||||
break
|
||||
case Transactions.rewardType.enrollment:
|
||||
description = intl.formatMessage({ id: "Sign up bonus" })
|
||||
description = intl.formatMessage({
|
||||
defaultMessage: "Sign up bonus",
|
||||
})
|
||||
break
|
||||
case Transactions.rewardType.mastercard_points:
|
||||
description = intl.formatMessage({ id: "Scandic Friends Mastercard" })
|
||||
description = intl.formatMessage({
|
||||
defaultMessage: "Scandic Friends Mastercard",
|
||||
})
|
||||
break
|
||||
case Transactions.rewardType.tui_points:
|
||||
description = intl.formatMessage({ id: "TUI Points" })
|
||||
description = intl.formatMessage({
|
||||
defaultMessage: "TUI Points",
|
||||
})
|
||||
|
||||
case Transactions.rewardType.pointShop:
|
||||
description = intl.formatMessage({ id: "Scandic Friends Point Shop" })
|
||||
description = intl.formatMessage({
|
||||
defaultMessage: "Scandic Friends Point Shop",
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,18 @@ export default function ClientTable({ transactions }: ClientTableProps) {
|
||||
const intl = useIntl()
|
||||
|
||||
const tableHeadings = [
|
||||
intl.formatMessage({ id: "Points" }),
|
||||
intl.formatMessage({ id: "Description" }),
|
||||
intl.formatMessage({ id: "Booking number" }),
|
||||
intl.formatMessage({ id: "Arrival date" }),
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Points",
|
||||
}),
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Description",
|
||||
}),
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Booking number",
|
||||
}),
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Arrival date",
|
||||
}),
|
||||
]
|
||||
|
||||
return (
|
||||
@@ -44,7 +52,9 @@ export default function ClientTable({ transactions }: ClientTableProps) {
|
||||
) : (
|
||||
<Table.TR className={styles.placeholder}>
|
||||
<Table.TD colSpan={tableHeadings.length}>
|
||||
{intl.formatMessage({ id: "No transactions available" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "No transactions available",
|
||||
})}
|
||||
</Table.TD>
|
||||
</Table.TR>
|
||||
)}
|
||||
|
||||
@@ -22,8 +22,12 @@ export default function ExpiringPointsTable({
|
||||
const expiration = dt(expirationDate).locale(lang).format("DD MMM YYYY")
|
||||
|
||||
const tableHeadings = [
|
||||
intl.formatMessage({ id: "Points" }),
|
||||
intl.formatMessage({ id: "Expiration Date" }),
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Points",
|
||||
}),
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Expiration Date",
|
||||
}),
|
||||
]
|
||||
|
||||
return (
|
||||
|
||||
@@ -47,12 +47,16 @@ export default async function NextLevelRewardsBlock({
|
||||
<article key={reward.reward_id} className={styles.card}>
|
||||
<Chip>
|
||||
<Lock height={16} />
|
||||
{intl.formatMessage({ id: "Level up to unlock" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Level up to unlock",
|
||||
})}
|
||||
</Chip>
|
||||
<div className={styles.textContainer}>
|
||||
<Body color="peach50" textAlign="center">
|
||||
{intl.formatMessage(
|
||||
{ id: "As our {level}" },
|
||||
{
|
||||
defaultMessage: "As our {level}",
|
||||
},
|
||||
{ level: nextLevelRewards.level?.name }
|
||||
)}
|
||||
</Body>
|
||||
|
||||
@@ -26,7 +26,11 @@ export default function ActiveRedeemedBadge() {
|
||||
>
|
||||
<MaterialIcon icon="check_circle" color="Icon/Feedback/Success" />
|
||||
</motion.div>
|
||||
<Caption>{intl.formatMessage({ id: "Active" })}</Caption>
|
||||
<Caption>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Active",
|
||||
})}
|
||||
</Caption>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -17,17 +17,18 @@ export function ConfirmClose({ close }: { close: VoidFunction }) {
|
||||
<div className={styles.modalContent}>
|
||||
<Title level="h3" textAlign="center" textTransform="regular">
|
||||
{intl.formatMessage({
|
||||
id: "If you close this your benefit will be removed",
|
||||
defaultMessage: "If you close this your benefit will be removed",
|
||||
})}
|
||||
</Title>
|
||||
<Body>
|
||||
{intl.formatMessage({
|
||||
id: "Have you showed this benefit to the hotel staff?",
|
||||
defaultMessage: "Have you showed this benefit to the hotel staff?",
|
||||
})}
|
||||
</Body>
|
||||
<Body>
|
||||
{intl.formatMessage({
|
||||
id: "If not, please go back and do so before you close this. Once you close this your benefit will be void and removed from My Benefits.",
|
||||
defaultMessage:
|
||||
"If not, please go back and do so before you close this. Once you close this your benefit will be void and removed from My Benefits.",
|
||||
})}
|
||||
</Body>
|
||||
</div>
|
||||
@@ -37,10 +38,14 @@ export function ConfirmClose({ close }: { close: VoidFunction }) {
|
||||
intent="primary"
|
||||
theme="base"
|
||||
>
|
||||
{intl.formatMessage({ id: "No, go back" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "No, go back",
|
||||
})}
|
||||
</Button>
|
||||
<Button onClick={close} intent="secondary" theme="base">
|
||||
{intl.formatMessage({ id: "Yes, close and remove benefit" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Yes, close and remove benefit",
|
||||
})}
|
||||
</Button>
|
||||
</footer>
|
||||
</>
|
||||
|
||||
@@ -29,7 +29,9 @@ export default function Campaign({ reward }: { reward: Campaign }) {
|
||||
<Body textAlign="center">{reward.description}</Body>
|
||||
<div className={styles.rewardBadge}>
|
||||
<Caption textAlign="center" color="uiTextHighContrast" type="bold">
|
||||
{intl.formatMessage({ id: "Promo code" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Promo code",
|
||||
})}
|
||||
</Caption>
|
||||
<Caption textAlign="center" color="uiTextHighContrast">
|
||||
{reward.operaRewardId}
|
||||
@@ -41,9 +43,17 @@ export default function Campaign({ reward }: { reward: Campaign }) {
|
||||
onClick={() => {
|
||||
try {
|
||||
navigator.clipboard.writeText(reward.operaRewardId)
|
||||
toast.success(intl.formatMessage({ id: "Copied to clipboard" }))
|
||||
toast.success(
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Copied to clipboard",
|
||||
})
|
||||
)
|
||||
} catch {
|
||||
toast.error(intl.formatMessage({ id: "Failed to copy" }))
|
||||
toast.error(
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Failed to copy",
|
||||
})
|
||||
)
|
||||
}
|
||||
}}
|
||||
type="button"
|
||||
@@ -53,7 +63,9 @@ export default function Campaign({ reward }: { reward: Campaign }) {
|
||||
intent="primary"
|
||||
>
|
||||
<MaterialIcon icon="content_copy" color="CurrentColor" />
|
||||
{intl.formatMessage({ id: "Copy promotion code" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Copy promotion code",
|
||||
})}
|
||||
</Button>
|
||||
</footer>
|
||||
</>
|
||||
|
||||
@@ -86,7 +86,9 @@ export default function Tier({
|
||||
intent="primary"
|
||||
theme="base"
|
||||
>
|
||||
{intl.formatMessage({ id: "Redeem benefit" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Redeem benefit",
|
||||
})}
|
||||
</Button>
|
||||
</footer>
|
||||
)}
|
||||
@@ -99,14 +101,18 @@ export default function Tier({
|
||||
intent="primary"
|
||||
theme="base"
|
||||
>
|
||||
{intl.formatMessage({ id: "Yes, redeem" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Yes, redeem",
|
||||
})}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setRedeemStep("initial")}
|
||||
intent="secondary"
|
||||
theme="base"
|
||||
>
|
||||
{intl.formatMessage({ id: "Go back" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Go back",
|
||||
})}
|
||||
</Button>
|
||||
</footer>
|
||||
)}
|
||||
|
||||
@@ -15,7 +15,9 @@ export default function MembershipNumberBadge({
|
||||
<div className={styles.rewardBadge}>
|
||||
<Caption textAlign="center" color="uiTextHighContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "Membership ID: {id}" },
|
||||
{
|
||||
defaultMessage: "Membership ID: {id}",
|
||||
},
|
||||
{ id: membershipNumber }
|
||||
)}
|
||||
</Caption>
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function TimedRedeemedBadge() {
|
||||
<MaterialIcon icon="check_circle" color="Icon/Feedback/Success" />
|
||||
<Caption>
|
||||
{intl.formatMessage({
|
||||
id: "Redeemed & valid through:",
|
||||
defaultMessage: "Redeemed & valid through:",
|
||||
})}
|
||||
</Caption>
|
||||
</div>
|
||||
|
||||
@@ -71,8 +71,12 @@ export default function Redeem({ reward, membershipNumber }: RedeemProps) {
|
||||
>
|
||||
<Button intent="primary" fullWidth>
|
||||
{reward.redeemLocation === "Non-redeemable"
|
||||
? intl.formatMessage({ id: "How to use" })
|
||||
: intl.formatMessage({ id: "Open" })}
|
||||
? intl.formatMessage({
|
||||
defaultMessage: "How to use",
|
||||
})
|
||||
: intl.formatMessage({
|
||||
defaultMessage: "Open",
|
||||
})}
|
||||
</Button>
|
||||
<MotionOverlay
|
||||
className={styles.overlay}
|
||||
|
||||
@@ -21,11 +21,17 @@ export default function ScriptedRewardText({
|
||||
: null
|
||||
}
|
||||
case "Campaign":
|
||||
return intl.formatMessage({ id: "Campaign" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Campaign",
|
||||
})
|
||||
case "Surprise":
|
||||
return intl.formatMessage({ id: "Surprise!" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Surprise!",
|
||||
})
|
||||
case "Member-voucher":
|
||||
return intl.formatMessage({ id: "Voucher" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Voucher",
|
||||
})
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -17,17 +17,24 @@ export function UnlinkSAS() {
|
||||
return (
|
||||
<Dialog
|
||||
titleText={intl.formatMessage({
|
||||
id: "Are you sure you want to unlink your account?",
|
||||
defaultMessage: "Are you sure you want to unlink your account?",
|
||||
})}
|
||||
bodyText={intl.formatMessage({
|
||||
id: "This will remove any membership level upgrades gained from the linking.",
|
||||
defaultMessage:
|
||||
"This will remove any membership level upgrades gained from the linking.",
|
||||
})}
|
||||
cancelButtonText={intl.formatMessage({
|
||||
defaultMessage: "Go back",
|
||||
})}
|
||||
proceedText={intl.formatMessage({
|
||||
defaultMessage: "Yes, unlink my accounts",
|
||||
})}
|
||||
cancelButtonText={intl.formatMessage({ id: "Go back" })}
|
||||
proceedText={intl.formatMessage({ id: "Yes, unlink my accounts" })}
|
||||
proceedHref={`/${params.lang}/sas-x-scandic/login?intent=unlink`}
|
||||
trigger={
|
||||
<Button intent="text" theme="base">
|
||||
{intl.formatMessage({ id: "Unlink accounts" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Unlink accounts",
|
||||
})}
|
||||
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
||||
</Button>
|
||||
}
|
||||
|
||||
@@ -58,7 +58,8 @@ export default async function SASLinkedAccount({
|
||||
<p className={styles.caption}>
|
||||
<MaterialIcon icon="info" size={20} />
|
||||
{intl.formatMessage({
|
||||
id: "Changes in your level match can take up to 24 hours to be displayed.",
|
||||
defaultMessage:
|
||||
"Changes in your level match can take up to 24 hours to be displayed.",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
@@ -96,20 +97,37 @@ async function MatchedAccountInfo() {
|
||||
<section className={styles.matchedAccountSection}>
|
||||
<div className={styles.accountDetails}>
|
||||
<div className={styles.stack}>
|
||||
<Label>{intl.formatMessage({ id: "Linked account" })}</Label>
|
||||
<Label>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Linked account",
|
||||
})}
|
||||
</Label>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>{intl.formatMessage({ id: "SAS EuroBonus" })}</p>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "SAS EuroBonus",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={styles.stack}>
|
||||
<Label>{intl.formatMessage({ id: "Level" })}</Label>
|
||||
<Label>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Level",
|
||||
})}
|
||||
</Label>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>{sasLevelName}</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={cx(styles.stack, styles.accountMemberNumber)}>
|
||||
<Label>{intl.formatMessage({ id: "Membership number" })}</Label>
|
||||
<Label>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Membership number",
|
||||
})}
|
||||
</Label>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
<p className={styles.textRight}>EB{sasMembershipNumber}</p>
|
||||
</Typography>
|
||||
</div>
|
||||
@@ -137,17 +155,33 @@ async function MatchedAccountInfoSkeleton() {
|
||||
<section className={styles.matchedAccountSection}>
|
||||
<div className={styles.accountDetails}>
|
||||
<div className={styles.stack}>
|
||||
<Label>{intl.formatMessage({ id: "Linked account" })}</Label>
|
||||
<Label>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Linked account",
|
||||
})}
|
||||
</Label>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>{intl.formatMessage({ id: "SAS EuroBonus" })}</p>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "SAS EuroBonus",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={styles.stack}>
|
||||
<Label>{intl.formatMessage({ id: "Level" })}</Label>
|
||||
<Label>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Level",
|
||||
})}
|
||||
</Label>
|
||||
<SkeletonShimmer width="6ch" height="24px" />
|
||||
</div>
|
||||
<div className={cx(styles.stack, styles.accountMemberNumber)}>
|
||||
<Label>{intl.formatMessage({ id: "Membership number" })}</Label>
|
||||
<Label>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Membership number",
|
||||
})}
|
||||
</Label>
|
||||
<SkeletonShimmer width="10ch" height="24px" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -188,19 +222,22 @@ async function TierMatchMessage({
|
||||
const messageMap: Record<MatchState, ReactNode> = {
|
||||
boostedBySAS: intl.formatMessage(
|
||||
{
|
||||
id: "<sasMark>EuroBonus {sasLevelName}</sasMark> has upgraded your Scandic Friends level to <scandicMark>{scandicLevelName}</scandicMark>.",
|
||||
defaultMessage:
|
||||
"<sasMark>EuroBonus {sasLevelName}</sasMark> has upgraded your Scandic Friends level to <scandicMark>{scandicLevelName}</scandicMark>.",
|
||||
},
|
||||
messageValues
|
||||
),
|
||||
boostedByScandic: intl.formatMessage(
|
||||
{
|
||||
id: "Your Scandic Friends level <scandicMark>{scandicLevelName}</scandicMark> has upgraded you to <sasMark>EuroBonus {sasLevelName}</sasMark>.",
|
||||
defaultMessage:
|
||||
"Your Scandic Friends level <scandicMark>{scandicLevelName}</scandicMark> has upgraded you to <sasMark>EuroBonus {sasLevelName}</sasMark>.",
|
||||
},
|
||||
messageValues
|
||||
),
|
||||
noBoost: intl.formatMessage(
|
||||
{
|
||||
id: "<sasMark>EuroBonus {sasLevelName}</sasMark> and <scandicMark>{scandicLevelName}</scandicMark> are equally matched tiers. Level up in one of your memberships to qualify for an upgrade!",
|
||||
defaultMessage:
|
||||
"<sasMark>EuroBonus {sasLevelName}</sasMark> and <scandicMark>{scandicLevelName}</scandicMark> are equally matched tiers. Level up in one of your memberships to qualify for an upgrade!",
|
||||
},
|
||||
messageValues
|
||||
),
|
||||
@@ -214,7 +251,11 @@ async function TierMatchMessage({
|
||||
|
||||
return (
|
||||
<div className={styles.stack}>
|
||||
<Label>{intl.formatMessage({ id: "Level match status" })}</Label>
|
||||
<Label>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Level match status",
|
||||
})}
|
||||
</Label>
|
||||
<div className={styles.tierMatchText}>
|
||||
<div className={styles.iconWrapper}>{iconMap[matchState]}</div>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
@@ -230,7 +271,11 @@ async function TierMatchMessageSkeleton() {
|
||||
|
||||
return (
|
||||
<div className={styles.stack}>
|
||||
<Label>{intl.formatMessage({ id: "Level match status" })}</Label>
|
||||
<Label>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Level match status",
|
||||
})}
|
||||
</Label>
|
||||
<div className={styles.tierMatchText}>
|
||||
<SkeletonShimmer width="250px" height="24px" />
|
||||
</div>
|
||||
@@ -256,7 +301,11 @@ async function TierMatchExpiration({
|
||||
|
||||
return (
|
||||
<div className={styles.stack}>
|
||||
<Label>{intl.formatMessage({ id: "Upgrade valid until" })}</Label>
|
||||
<Label>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Upgrade valid until",
|
||||
})}
|
||||
</Label>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{matchState === "boostedBySAS"
|
||||
|
||||
@@ -78,18 +78,28 @@ async function TransferPointsFormContent({
|
||||
<div>
|
||||
<div className={styles.labelWithIcon}>
|
||||
<Typography variant="Tag/sm">
|
||||
<p>{intl.formatMessage({ id: "Transfer from" })}</p>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Transfer from",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<MaterialIcon icon="upload" />
|
||||
</div>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<p>{intl.formatMessage({ id: "SAS EuroBonus" })}</p>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "SAS EuroBonus",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Typography variant="Tag/sm">
|
||||
<p className={styles.balanceLabel}>
|
||||
{intl.formatMessage({ id: "Balance" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Balance",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
{sasPoints === null ? (
|
||||
@@ -102,7 +112,9 @@ async function TransferPointsFormContent({
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{ id: "{points, number} p" },
|
||||
{
|
||||
defaultMessage: "{points, number} p",
|
||||
},
|
||||
{ points: sasPoints }
|
||||
)}
|
||||
</p>
|
||||
@@ -115,7 +127,7 @@ async function TransferPointsFormContent({
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "You have no points to transfer.",
|
||||
defaultMessage: "You have no points to transfer.",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
@@ -126,17 +138,27 @@ async function TransferPointsFormContent({
|
||||
<div className={styles.labelWithIcon}>
|
||||
<MaterialIcon icon="download" />
|
||||
<Typography variant="Tag/sm">
|
||||
<p>{intl.formatMessage({ id: "Transfer to" })}</p>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Transfer to",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<p>{intl.formatMessage({ id: "Scandic Friends" })}</p>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Scandic Friends",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Typography variant="Tag/sm">
|
||||
<p className={styles.balanceLabel}>
|
||||
{intl.formatMessage({ id: "Balance" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Balance",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
{scandicPoints === null ? (
|
||||
@@ -149,7 +171,9 @@ async function TransferPointsFormContent({
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{ id: "{points, number} p" },
|
||||
{
|
||||
defaultMessage: "{points, number} p",
|
||||
},
|
||||
{ points: scandicPoints }
|
||||
)}
|
||||
</p>
|
||||
@@ -167,7 +191,7 @@ async function TransferPointsFormContent({
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<p style={{ color: "var(--Text-Tertiary)" }}>
|
||||
{intl.formatMessage({
|
||||
id: "Transferred points will not be level qualifying",
|
||||
defaultMessage: "Transferred points will not be level qualifying",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
|
||||
@@ -66,7 +66,9 @@ export function TransferPointsFormClient({
|
||||
className={styles.slider}
|
||||
// Set max value to 1 if sasPoints is 0 since slider requires a range
|
||||
maxValue={hasNoSasPoints ? 1 : sasPoints}
|
||||
aria-label={intl.formatMessage({ id: "EB points to transfer" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "EB points to transfer",
|
||||
})}
|
||||
formatOptions={{
|
||||
useGrouping: true,
|
||||
maximumFractionDigits: 0,
|
||||
@@ -85,7 +87,9 @@ export function TransferPointsFormClient({
|
||||
<div className={styles.inputsWrapper}>
|
||||
<TextField type="number" isDisabled={disabled}>
|
||||
<AriaInputWithLabel
|
||||
label={intl.formatMessage({ id: "EB points to transfer" })}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "EB points to transfer",
|
||||
})}
|
||||
type="number"
|
||||
min={0}
|
||||
value={pointState ?? ""}
|
||||
@@ -105,13 +109,17 @@ export function TransferPointsFormClient({
|
||||
<p className={styles.conversionRate}>
|
||||
{/* TODO maybe dynamic string based on exchange rate */}
|
||||
{intl.formatMessage({
|
||||
id: "1 EuroBonus point = 2 Scandic Friends points",
|
||||
defaultMessage: "1 EuroBonus point = 2 Scandic Friends points",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<div className={styles.pointsOutput}>
|
||||
<Typography variant="Label/xsRegular">
|
||||
<p>{intl.formatMessage({ id: "SF points to receive" })}</p>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "SF points to receive",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{intl.formatNumber(calculatedPoints)}</p>
|
||||
@@ -174,7 +182,9 @@ function ConfirmModal({
|
||||
onClick={() => handleToggle(true)}
|
||||
disabled={disabled}
|
||||
>
|
||||
{intl.formatMessage({ id: "Transfer points" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Transfer points",
|
||||
})}
|
||||
</Button>
|
||||
<Modal isOpen={isOpen} onToggle={handleToggle}>
|
||||
<div className={styles.modalContainer}>
|
||||
@@ -186,18 +196,25 @@ function ConfirmModal({
|
||||
/>
|
||||
<Typography variant="Title/Subtitle/lg">
|
||||
<h3>
|
||||
{intl.formatMessage({ id: "Proceed with point transfer?" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Proceed with point transfer?",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<div>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{intl.formatMessage({ id: "You are about to exchange:" })}</p>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "You are about to exchange:",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "<bold>{sasPoints, number} EuroBonus points</bold> to <bold>{scandicPoints, number} Scandic Friends points</bold>",
|
||||
defaultMessage:
|
||||
"<bold>{sasPoints, number} EuroBonus points</bold> to <bold>{scandicPoints, number} Scandic Friends points</bold>",
|
||||
},
|
||||
{
|
||||
sasPoints,
|
||||
@@ -215,7 +232,8 @@ function ConfirmModal({
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<p className={styles.expiryText}>
|
||||
{intl.formatMessage({
|
||||
id: "Your exchanged points will retain their original expiry date with a maximum validity of 12 months.",
|
||||
defaultMessage:
|
||||
"Your exchanged points will retain their original expiry date with a maximum validity of 12 months.",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
@@ -227,7 +245,7 @@ function ConfirmModal({
|
||||
color="none"
|
||||
>
|
||||
{intl.formatMessage({
|
||||
id: "Yes, I want to transfer my points",
|
||||
defaultMessage: "Yes, I want to transfer my points",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
@@ -237,7 +255,9 @@ function ConfirmModal({
|
||||
theme="base"
|
||||
onClick={() => handleToggle(false)}
|
||||
>
|
||||
{intl.formatMessage({ id: "Cancel" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Cancel",
|
||||
})}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@ export default async function EmptyPreviousStaysBlock() {
|
||||
<section className={styles.container}>
|
||||
<Title as="h4" level="h3" color="red" textAlign="center">
|
||||
{intl.formatMessage({
|
||||
id: "You have no previous stays.",
|
||||
defaultMessage: "You have no previous stays.",
|
||||
})}
|
||||
</Title>
|
||||
</section>
|
||||
|
||||
@@ -30,7 +30,9 @@ export default function ShowMoreButton({
|
||||
size={20}
|
||||
color="CurrentColor"
|
||||
/>
|
||||
{intl.formatMessage({ id: "Show more" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Show more",
|
||||
})}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -28,14 +28,20 @@ export default async function EmptyUpcomingStaysBlock() {
|
||||
className={styles.title}
|
||||
textAlign="center"
|
||||
>
|
||||
{intl.formatMessage({ id: "You have no upcoming stays." })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "You have no upcoming stays.",
|
||||
})}
|
||||
<span className={styles.burgundyTitle}>
|
||||
{intl.formatMessage({ id: "Where should you go next?" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Where should you go next?",
|
||||
})}
|
||||
</span>
|
||||
</Title>
|
||||
</div>
|
||||
<Link href={href} className={styles.link} color="peach80">
|
||||
{intl.formatMessage({ id: "Get inspired" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Get inspired",
|
||||
})}
|
||||
<MaterialIcon icon="arrow_forward" color="CurrentColor" />
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
@@ -59,6 +59,7 @@ export default function StayCard({ stay }: StayCardProps) {
|
||||
<Caption asChild>
|
||||
<time dateTime={arrivalDateTime}>{arrivalDate}</time>
|
||||
</Caption>
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
{" - "}
|
||||
<Caption asChild>
|
||||
<time dateTime={departDateTime}>{departDate}</time>
|
||||
|
||||
@@ -28,14 +28,20 @@ export default async function EmptyUpcomingStaysBlock() {
|
||||
className={styles.title}
|
||||
textAlign="center"
|
||||
>
|
||||
{intl.formatMessage({ id: "You have no upcoming stays." })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "You have no upcoming stays.",
|
||||
})}
|
||||
<span className={styles.burgundyTitle}>
|
||||
{intl.formatMessage({ id: "Where should you go next?" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Where should you go next?",
|
||||
})}
|
||||
</span>
|
||||
</Title>
|
||||
</div>
|
||||
<Link href={href} className={styles.link} color="peach80">
|
||||
{intl.formatMessage({ id: "Get inspired" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Get inspired",
|
||||
})}
|
||||
<MaterialIcon icon="arrow_forward" color="CurrentColor" />
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
@@ -56,7 +56,9 @@ export default async function HotelListingItem({
|
||||
</div>
|
||||
<Caption color="uiTextPlaceholder">
|
||||
{intl.formatMessage(
|
||||
{ id: "{number} km to city center" },
|
||||
{
|
||||
defaultMessage: "{number} km to city center",
|
||||
},
|
||||
{
|
||||
number: getSingleDecimal(
|
||||
hotel.location.distanceToCentre / 1000
|
||||
|
||||
@@ -21,7 +21,9 @@ export function getTypeSpecificInformation(
|
||||
alt: images.metaData.altText,
|
||||
},
|
||||
cta: {
|
||||
text: intl.formatMessage({ id: "See hotel details" }),
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "See hotel details",
|
||||
}),
|
||||
url,
|
||||
openInNewTab: false,
|
||||
},
|
||||
@@ -41,7 +43,9 @@ export function getTypeSpecificInformation(
|
||||
}
|
||||
if (meetingUrl) {
|
||||
data.cta = {
|
||||
text: intl.formatMessage({ id: "Book a meeting" }),
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Book a meeting",
|
||||
}),
|
||||
url: meetingUrl,
|
||||
openInNewTab: true,
|
||||
}
|
||||
|
||||
@@ -53,22 +53,31 @@ export default function MobileToggleButton({
|
||||
}, 0)
|
||||
|
||||
const totalNightsMsg = intl.formatMessage(
|
||||
{ id: "{totalNights, plural, one {# night} other {# nights}}" },
|
||||
{
|
||||
defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
|
||||
},
|
||||
{ totalNights }
|
||||
)
|
||||
|
||||
const totalAdultsMsg = intl.formatMessage(
|
||||
{ id: "{totalAdults, plural, one {# adult} other {# adults}}" },
|
||||
{
|
||||
defaultMessage: "{totalAdults, plural, one {# adult} other {# adults}}",
|
||||
},
|
||||
{ totalAdults }
|
||||
)
|
||||
|
||||
const totalChildrenMsg = intl.formatMessage(
|
||||
{ id: "{totalChildren, plural, one {# child} other {# children}}" },
|
||||
{
|
||||
defaultMessage:
|
||||
"{totalChildren, plural, one {# child} other {# children}}",
|
||||
},
|
||||
{ totalChildren }
|
||||
)
|
||||
|
||||
const totalRoomsMsg = intl.formatMessage(
|
||||
{ id: "{totalRooms, plural, one {# room} other {# rooms}}" },
|
||||
{
|
||||
defaultMessage: "{totalRooms, plural, one {# room} other {# rooms}}",
|
||||
},
|
||||
{ totalRooms }
|
||||
)
|
||||
|
||||
@@ -88,14 +97,18 @@ export default function MobileToggleButton({
|
||||
<span className={styles.block}>
|
||||
<Typography variant={"Body/Supporting text (caption)/smBold"}>
|
||||
<span className={styles.blockLabel}>
|
||||
{intl.formatMessage({ id: "Where to?" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Where to?",
|
||||
})}
|
||||
</span>
|
||||
</Typography>
|
||||
<Typography variant={"Body/Paragraph/mdRegular"}>
|
||||
<span className={styles.placeholder}>
|
||||
{searchTerm
|
||||
? searchTerm
|
||||
: intl.formatMessage({ id: "Destination" })}
|
||||
: intl.formatMessage({
|
||||
defaultMessage: "Destination",
|
||||
})}
|
||||
</span>
|
||||
</Typography>
|
||||
</span>
|
||||
@@ -108,7 +121,9 @@ export default function MobileToggleButton({
|
||||
<Typography variant={"Body/Paragraph/mdRegular"}>
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{ id: "{selectedFromDate} - {selectedToDate}" },
|
||||
{
|
||||
defaultMessage: "{selectedFromDate} - {selectedToDate}",
|
||||
},
|
||||
{
|
||||
selectedFromDate,
|
||||
selectedToDate,
|
||||
@@ -133,7 +148,8 @@ export default function MobileToggleButton({
|
||||
<span className={styles.locationAndDate}>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "{selectedFromDate} - {selectedToDate} ({totalNights}) {details}",
|
||||
defaultMessage:
|
||||
"{selectedFromDate} - {selectedToDate} ({totalNights}) {details}",
|
||||
},
|
||||
{
|
||||
selectedFromDate,
|
||||
@@ -162,7 +178,9 @@ export function MobileToggleButtonSkeleton() {
|
||||
<span className={styles.block}>
|
||||
<Typography variant={"Body/Supporting text (caption)/smBold"}>
|
||||
<span className={styles.blockLabel}>
|
||||
{intl.formatMessage({ id: "Where to?" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Where to?",
|
||||
})}
|
||||
</span>
|
||||
</Typography>
|
||||
<SkeletonShimmer display={"block"} height="24px" />
|
||||
@@ -172,7 +190,10 @@ export function MobileToggleButtonSkeleton() {
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span className={styles.blockLabel}>
|
||||
{intl.formatMessage(
|
||||
{ id: "{totalNights, plural, one {# night} other {# nights}}" },
|
||||
{
|
||||
defaultMessage:
|
||||
"{totalNights, plural, one {# night} other {# nights}}",
|
||||
},
|
||||
{ totalNights: 0 }
|
||||
)}
|
||||
</span>
|
||||
|
||||
@@ -22,7 +22,9 @@ export function CarouselPrevious({ className, ...props }: CarouselButtonProps) {
|
||||
<button
|
||||
className={cx(styles.button, styles.buttonPrev, className)}
|
||||
onClick={scrollPrev}
|
||||
aria-label={intl.formatMessage({ id: "Previous slide" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Previous slide",
|
||||
})}
|
||||
{...props}
|
||||
>
|
||||
<MaterialIcon color="Icon/Interactive/Default" icon="arrow_back" />
|
||||
@@ -41,7 +43,9 @@ export function CarouselNext({ className, ...props }: CarouselButtonProps) {
|
||||
<button
|
||||
className={cx(styles.button, styles.buttonNext, className)}
|
||||
onClick={scrollNext}
|
||||
aria-label={intl.formatMessage({ id: "Next slide" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Next slide",
|
||||
})}
|
||||
{...props}
|
||||
>
|
||||
<MaterialIcon color="Icon/Interactive/Default" icon="arrow_forward" />
|
||||
|
||||
@@ -31,11 +31,18 @@ export default async function CityDataContainer({
|
||||
|
||||
const sortItems: SortItem[] = [
|
||||
{
|
||||
label: intl.formatMessage({ id: "Recommended" }),
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Recommended",
|
||||
}),
|
||||
value: SortOption.Recommended,
|
||||
isDefault: true,
|
||||
},
|
||||
{ label: intl.formatMessage({ id: "Name" }), value: SortOption.Name },
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Name",
|
||||
}),
|
||||
value: SortOption.Name,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
|
||||
@@ -31,7 +31,9 @@ export default function CityListingItem({ city }: CityListingItemProps) {
|
||||
images={galleryImages}
|
||||
fill
|
||||
title={intl.formatMessage(
|
||||
{ id: "{title} - Image gallery" },
|
||||
{
|
||||
defaultMessage: "{title} - Image gallery",
|
||||
},
|
||||
{ title: city.cityName }
|
||||
)}
|
||||
/>
|
||||
@@ -57,7 +59,9 @@ export default function CityListingItem({ city }: CityListingItemProps) {
|
||||
>
|
||||
<Link href={city.url}>
|
||||
{intl.formatMessage(
|
||||
{ id: "Explore {city}" },
|
||||
{
|
||||
defaultMessage: "Explore {city}",
|
||||
},
|
||||
{ city: city.cityName }
|
||||
)}
|
||||
</Link>
|
||||
|
||||
@@ -38,7 +38,8 @@ export default function CityListing() {
|
||||
<Subtitle type="two">
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "{count, plural, one {# Location} other {# Locations}}",
|
||||
defaultMessage:
|
||||
"{count, plural, one {# Location} other {# Locations}}",
|
||||
},
|
||||
{ count: activeCities.length }
|
||||
)}
|
||||
@@ -48,9 +49,12 @@ export default function CityListing() {
|
||||
{activeCities.length === 0 ? (
|
||||
<Alert
|
||||
type={AlertTypeEnum.Info}
|
||||
heading={intl.formatMessage({ id: "No matching locations found" })}
|
||||
heading={intl.formatMessage({
|
||||
defaultMessage: "No matching locations found",
|
||||
})}
|
||||
text={intl.formatMessage({
|
||||
id: "It looks like no location match your filters. Try adjusting your search to find the perfect stay.",
|
||||
defaultMessage:
|
||||
"It looks like no location match your filters. Try adjusting your search to find the perfect stay.",
|
||||
})}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -63,7 +63,9 @@ export default function HotelList() {
|
||||
<div className={styles.header}>
|
||||
<Body>
|
||||
{intl.formatMessage(
|
||||
{ id: "{count} hotels" },
|
||||
{
|
||||
defaultMessage: "{count} hotels",
|
||||
},
|
||||
{ count: visibleHotels.length }
|
||||
)}
|
||||
</Body>
|
||||
@@ -72,9 +74,12 @@ export default function HotelList() {
|
||||
{activeHotels.length === 0 ? (
|
||||
<Alert
|
||||
type={AlertTypeEnum.Info}
|
||||
heading={intl.formatMessage({ id: "No matching hotels found" })}
|
||||
heading={intl.formatMessage({
|
||||
defaultMessage: "No matching hotels found",
|
||||
})}
|
||||
text={intl.formatMessage({
|
||||
id: "It looks like no hotels match your filters. Try adjusting your search to find the perfect stay.",
|
||||
defaultMessage:
|
||||
"It looks like no hotels match your filters. Try adjusting your search to find the perfect stay.",
|
||||
})}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -67,7 +67,9 @@ export default function HotelListItem(data: DestinationPagesHotelData) {
|
||||
fill
|
||||
sizes="(min-width: 768px) 350px, 100vw"
|
||||
title={intl.formatMessage(
|
||||
{ id: "{title} - Image gallery" },
|
||||
{
|
||||
defaultMessage: "{title} - Image gallery",
|
||||
},
|
||||
{ title: hotel.name }
|
||||
)}
|
||||
/>
|
||||
@@ -93,7 +95,9 @@ export default function HotelListItem(data: DestinationPagesHotelData) {
|
||||
<Divider variant="vertical" color="beige" />
|
||||
<Caption color="uiTextPlaceholder">
|
||||
{intl.formatMessage(
|
||||
{ id: "{number} km to city center" },
|
||||
{
|
||||
defaultMessage: "{number} km to city center",
|
||||
},
|
||||
{
|
||||
number: getSingleDecimal(
|
||||
hotel.location.distanceToCentre / 1000
|
||||
@@ -120,7 +124,9 @@ export default function HotelListItem(data: DestinationPagesHotelData) {
|
||||
<div className={styles.ctaWrapper}>
|
||||
<Button intent="tertiary" theme="base" size="small" asChild>
|
||||
<Link href={url}>
|
||||
{intl.formatMessage({ id: "See hotel details" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "See hotel details",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -29,7 +29,9 @@ export default function CityList() {
|
||||
<div className={styles.header}>
|
||||
<Body>
|
||||
{intl.formatMessage(
|
||||
{ id: "{count} destinations" },
|
||||
{
|
||||
defaultMessage: "{count} destinations",
|
||||
},
|
||||
{ count: activeCities.length }
|
||||
)}
|
||||
</Body>
|
||||
@@ -38,9 +40,12 @@ export default function CityList() {
|
||||
{activeCities.length === 0 ? (
|
||||
<Alert
|
||||
type={AlertTypeEnum.Info}
|
||||
heading={intl.formatMessage({ id: "No matching locations found" })}
|
||||
heading={intl.formatMessage({
|
||||
defaultMessage: "No matching locations found",
|
||||
})}
|
||||
text={intl.formatMessage({
|
||||
id: "It looks like no location match your filters. Try adjusting your search to find the perfect stay.",
|
||||
defaultMessage:
|
||||
"It looks like no location match your filters. Try adjusting your search to find the perfect stay.",
|
||||
})}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -29,7 +29,9 @@ export default function CityListItem({ city }: CityListItemProps) {
|
||||
images={galleryImages}
|
||||
fill
|
||||
title={intl.formatMessage(
|
||||
{ id: "{title} - Image gallery" },
|
||||
{
|
||||
defaultMessage: "{title} - Image gallery",
|
||||
},
|
||||
{ title: city.cityName }
|
||||
)}
|
||||
/>
|
||||
@@ -47,7 +49,9 @@ export default function CityListItem({ city }: CityListItemProps) {
|
||||
<Button intent="tertiary" theme="base" size="small" asChild>
|
||||
<Link href={city.url}>
|
||||
{intl.formatMessage(
|
||||
{ id: "Explore {city}" },
|
||||
{
|
||||
defaultMessage: "Explore {city}",
|
||||
},
|
||||
{ city: city.cityName }
|
||||
)}
|
||||
</Link>
|
||||
|
||||
@@ -18,15 +18,24 @@ export function getHeadingText(
|
||||
|
||||
if (facilityFilter) {
|
||||
return intl.formatMessage(
|
||||
{ id: "Hotels with {filter} in {location}" },
|
||||
{
|
||||
defaultMessage: "Hotels with {filter} in {location}",
|
||||
},
|
||||
{ location, filter: facilityFilter.name }
|
||||
)
|
||||
} else if (surroudingsFilter) {
|
||||
return intl.formatMessage(
|
||||
{ id: "Hotels near {filter} in {location}" },
|
||||
{
|
||||
defaultMessage: "Hotels near {filter} in {location}",
|
||||
},
|
||||
{ location, filter: surroudingsFilter.name }
|
||||
)
|
||||
}
|
||||
}
|
||||
return intl.formatMessage({ id: "Hotels in {location}" }, { location })
|
||||
return intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Hotels in {location}",
|
||||
},
|
||||
{ location }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export default async function Destination({
|
||||
const intl = await getIntl()
|
||||
const accordionSubtitle = intl.formatMessage(
|
||||
{
|
||||
id: "{amount, plural, one {# hotel} other {# hotels}}",
|
||||
defaultMessage: "{amount, plural, one {# hotel} other {# hotels}}",
|
||||
},
|
||||
{ amount: numberOfHotels }
|
||||
)
|
||||
@@ -36,10 +36,14 @@ export default async function Destination({
|
||||
color="baseTextMediumContrast"
|
||||
textDecoration="underline"
|
||||
>
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
{`${city.name} (${city.hotelCount})`}
|
||||
</Link>
|
||||
) : (
|
||||
<Body>{`${city.name} (${city.hotelCount})`}</Body>
|
||||
<>
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
<Body>{`${city.name} (${city.hotelCount})`}</Body>
|
||||
</>
|
||||
)}
|
||||
</li>
|
||||
) : null
|
||||
@@ -49,7 +53,7 @@ export default async function Destination({
|
||||
<Link href={countryUrl} variant="icon" color="burgundy" weight="bold">
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "View all hotels in {country}",
|
||||
defaultMessage: "View all hotels in {country}",
|
||||
},
|
||||
{ country: country }
|
||||
)}
|
||||
|
||||
@@ -18,7 +18,9 @@ export default async function HotelsSection() {
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<Title level="h4" as="h2" textAlign="center">
|
||||
{intl.formatMessage({ id: "Explore all our hotels" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Explore all our hotels",
|
||||
})}
|
||||
</Title>
|
||||
<DestinationsList destinations={destinations} />
|
||||
</section>
|
||||
|
||||
@@ -60,14 +60,16 @@ export function ClientInline({
|
||||
<div className={styles.fields}>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<Label className={styles.label}>
|
||||
{intl.formatMessage({ id: "Where to?" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Where to?",
|
||||
})}
|
||||
</Label>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<Input
|
||||
className={styles.input}
|
||||
placeholder={intl.formatMessage({
|
||||
id: "Hotels & Destinations",
|
||||
defaultMessage: "Hotels & Destinations",
|
||||
})}
|
||||
onChange={(evt) => {
|
||||
startTransition(() => {
|
||||
@@ -83,7 +85,11 @@ export function ClientInline({
|
||||
|
||||
{state.value !== "" && (
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<ButtonRAC className={styles.clearButton}>Clear</ButtonRAC>
|
||||
<ButtonRAC className={styles.clearButton}>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Clear",
|
||||
})}
|
||||
</ButtonRAC>
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
@@ -96,7 +102,9 @@ export function ClientInline({
|
||||
type="submit"
|
||||
>
|
||||
<MaterialIcon icon="search" color="CurrentColor" />
|
||||
{intl.formatMessage({ id: "Search" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Search",
|
||||
})}
|
||||
</Button>
|
||||
</Typography>
|
||||
</form>
|
||||
@@ -113,7 +121,9 @@ export function ClientInline({
|
||||
>
|
||||
{showResults ? (
|
||||
<ResultsMemo
|
||||
aria-label={intl.formatMessage({ id: "Results" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Results",
|
||||
})}
|
||||
results={results}
|
||||
onAction={onAction}
|
||||
renderEmptyState={true}
|
||||
@@ -122,7 +132,7 @@ export function ClientInline({
|
||||
{showHistory ? (
|
||||
<ResultsMemo
|
||||
aria-label={intl.formatMessage({
|
||||
id: "Latest searches",
|
||||
defaultMessage: "Latest searches",
|
||||
})}
|
||||
results={latest}
|
||||
onAction={onAction}
|
||||
|
||||
@@ -45,12 +45,16 @@ export function ClientModal({
|
||||
<span>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span className={styles.label}>
|
||||
{intl.formatMessage({ id: "Where to?" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Where to?",
|
||||
})}
|
||||
</span>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span className={styles.placeholder}>
|
||||
{intl.formatMessage({ id: "Hotels & Destinations" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Hotels & Destinations",
|
||||
})}
|
||||
</span>
|
||||
</Typography>
|
||||
</span>
|
||||
@@ -62,12 +66,16 @@ export function ClientModal({
|
||||
<Modal className={styles.modal}>
|
||||
<Dialog className={styles.dialog}>
|
||||
<Heading level={2} className="sr-only">
|
||||
{intl.formatMessage({ id: "Find a location" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Find a location",
|
||||
})}
|
||||
</Heading>
|
||||
<ButtonRAC
|
||||
className={styles.closeButton}
|
||||
slot="close"
|
||||
aria-label={intl.formatMessage({ id: "Close" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Close",
|
||||
})}
|
||||
>
|
||||
<MaterialIcon icon="close" color="CurrentColor" />
|
||||
</ButtonRAC>
|
||||
@@ -91,14 +99,16 @@ export function ClientModal({
|
||||
>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<Label className={styles.label}>
|
||||
{intl.formatMessage({ id: "Where to?" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Where to?",
|
||||
})}
|
||||
</Label>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<Input
|
||||
className={styles.input}
|
||||
placeholder={intl.formatMessage({
|
||||
id: "Hotels & Destinations",
|
||||
defaultMessage: "Hotels & Destinations",
|
||||
})}
|
||||
onChange={(evt) => {
|
||||
startTransition(() => {
|
||||
@@ -115,7 +125,9 @@ export function ClientModal({
|
||||
{state.value !== "" && (
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<ButtonRAC className={styles.clearButton}>
|
||||
Clear
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Clear",
|
||||
})}
|
||||
</ButtonRAC>
|
||||
</Typography>
|
||||
)}
|
||||
@@ -132,7 +144,9 @@ export function ClientModal({
|
||||
>
|
||||
{showResults ? (
|
||||
<ResultsMemo
|
||||
aria-label={intl.formatMessage({ id: "Results" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Results",
|
||||
})}
|
||||
results={results}
|
||||
onAction={onAction}
|
||||
renderEmptyState={true}
|
||||
@@ -141,7 +155,7 @@ export function ClientModal({
|
||||
{showHistory ? (
|
||||
<ResultsMemo
|
||||
aria-label={intl.formatMessage({
|
||||
id: "Latest searches",
|
||||
defaultMessage: "Latest searches",
|
||||
})}
|
||||
results={latest}
|
||||
onAction={onAction}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function ResultsSkeleton() {
|
||||
<Typography variant="Title/Overline/sm">
|
||||
<header className={styles.sectionHeader}>
|
||||
{intl.formatMessage({
|
||||
id: "Loading results",
|
||||
defaultMessage: "Loading results",
|
||||
})}
|
||||
</header>
|
||||
</Typography>
|
||||
|
||||
@@ -45,13 +45,16 @@ export function Results({
|
||||
<>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<Header className={styles.noResultsLabel}>
|
||||
{intl.formatMessage({ id: "No results" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "No results",
|
||||
})}
|
||||
</Header>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span className={styles.noResultsDescription}>
|
||||
{intl.formatMessage({
|
||||
id: "We couldn't find a matching location for your search.",
|
||||
defaultMessage:
|
||||
"We couldn't find a matching location for your search.",
|
||||
})}
|
||||
</span>
|
||||
</Typography>
|
||||
|
||||
@@ -158,7 +158,9 @@ export function JumpToClient<T extends JumpToData>({
|
||||
type: "clearHistory",
|
||||
closesModal: false,
|
||||
icon: <MaterialIcon icon="delete" color="CurrentColor" />,
|
||||
displayName: intl.formatMessage({ id: "Clear searches" }),
|
||||
displayName: intl.formatMessage({
|
||||
defaultMessage: "Clear searches",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ export default function InputForm() {
|
||||
<input
|
||||
type="text"
|
||||
placeholder={intl.formatMessage({
|
||||
id: "Find hotels and destinations",
|
||||
defaultMessage: "Find hotels and destinations",
|
||||
})}
|
||||
className={styles.formInput}
|
||||
/>
|
||||
|
||||
@@ -17,49 +17,63 @@ export function mapExperiencesToListData(
|
||||
Icon: (props: MaterialIconSetIconProps) => (
|
||||
<MaterialIcon icon="hiking" {...props} />
|
||||
),
|
||||
name: intl.formatMessage({ id: "Hiking" }),
|
||||
name: intl.formatMessage({
|
||||
defaultMessage: "Hiking",
|
||||
}),
|
||||
}
|
||||
case "Kayaking":
|
||||
return {
|
||||
Icon: (props: MaterialIconSetIconProps) => (
|
||||
<MaterialIcon icon="kayaking" {...props} />
|
||||
),
|
||||
name: intl.formatMessage({ id: "Kayaking" }),
|
||||
name: intl.formatMessage({
|
||||
defaultMessage: "Kayaking",
|
||||
}),
|
||||
}
|
||||
case "Bike friendly":
|
||||
return {
|
||||
Icon: (props: MaterialIconSetIconProps) => (
|
||||
<MaterialIcon icon="pedal_bike" {...props} />
|
||||
),
|
||||
name: intl.formatMessage({ id: "Bike friendly" }),
|
||||
name: intl.formatMessage({
|
||||
defaultMessage: "Bike friendly",
|
||||
}),
|
||||
}
|
||||
case "Museums":
|
||||
return {
|
||||
Icon: (props: MaterialIconSetIconProps) => (
|
||||
<MaterialIcon icon="museum" {...props} />
|
||||
),
|
||||
name: intl.formatMessage({ id: "Museums" }),
|
||||
name: intl.formatMessage({
|
||||
defaultMessage: "Museums",
|
||||
}),
|
||||
}
|
||||
case "Family friendly":
|
||||
return {
|
||||
Icon: (props: MaterialIconSetIconProps) => (
|
||||
<MaterialIcon icon="family_restroom" {...props} />
|
||||
),
|
||||
name: intl.formatMessage({ id: "Family friendly" }),
|
||||
name: intl.formatMessage({
|
||||
defaultMessage: "Family friendly",
|
||||
}),
|
||||
}
|
||||
case "City pulse":
|
||||
return {
|
||||
Icon: (props: MaterialIconSetIconProps) => (
|
||||
<MaterialIcon icon="location_city" {...props} />
|
||||
),
|
||||
name: intl.formatMessage({ id: "City pulse" }),
|
||||
name: intl.formatMessage({
|
||||
defaultMessage: "City pulse",
|
||||
}),
|
||||
}
|
||||
case "Nightlife":
|
||||
return {
|
||||
Icon: (props: MaterialIconSetIconProps) => (
|
||||
<MaterialIcon icon="nightlife" {...props} />
|
||||
),
|
||||
name: intl.formatMessage({ id: "Nightlife" }),
|
||||
name: intl.formatMessage({
|
||||
defaultMessage: "Nightlife",
|
||||
}),
|
||||
}
|
||||
default:
|
||||
return {
|
||||
|
||||
@@ -23,13 +23,22 @@ export default async function HotelDataContainer({
|
||||
|
||||
const sortItems: SortItem[] = [
|
||||
{
|
||||
label: intl.formatMessage({ id: "Distance to city center" }),
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Distance to city center",
|
||||
}),
|
||||
value: SortOption.Distance,
|
||||
isDefault: true,
|
||||
},
|
||||
{ label: intl.formatMessage({ id: "Name" }), value: SortOption.Name },
|
||||
{
|
||||
label: intl.formatMessage({ id: "TripAdvisor rating" }),
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "Name",
|
||||
}),
|
||||
value: SortOption.Name,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
defaultMessage: "TripAdvisor rating",
|
||||
}),
|
||||
value: SortOption.TripAdvisorRating,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -48,7 +48,9 @@ export default function HotelListingItem(data: DestinationPagesHotelData) {
|
||||
fill
|
||||
sizes="(min-width: 768px) 350px, 100vw"
|
||||
title={intl.formatMessage(
|
||||
{ id: "{title} - Image gallery" },
|
||||
{
|
||||
defaultMessage: "{title} - Image gallery",
|
||||
},
|
||||
{ title: hotel.name }
|
||||
)}
|
||||
/>
|
||||
@@ -72,7 +74,9 @@ export default function HotelListingItem(data: DestinationPagesHotelData) {
|
||||
<Divider variant="vertical" color="beige" />
|
||||
<Caption color="uiTextPlaceholder">
|
||||
{intl.formatMessage(
|
||||
{ id: "{number} km to city center" },
|
||||
{
|
||||
defaultMessage: "{number} km to city center",
|
||||
},
|
||||
{
|
||||
number: getSingleDecimal(
|
||||
hotel.location.distanceToCentre / 1000
|
||||
@@ -107,7 +111,9 @@ export default function HotelListingItem(data: DestinationPagesHotelData) {
|
||||
scroll={true}
|
||||
onClick={() => setActiveMarker(hotel.id)}
|
||||
>
|
||||
{intl.formatMessage({ id: "See on map" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "See on map",
|
||||
})}
|
||||
<MaterialIcon
|
||||
icon="chevron_right"
|
||||
size={20}
|
||||
@@ -123,7 +129,9 @@ export default function HotelListingItem(data: DestinationPagesHotelData) {
|
||||
<div className={styles.ctaWrapper}>
|
||||
<Button intent="tertiary" theme="base" size="small" asChild>
|
||||
<Link href={url}>
|
||||
{intl.formatMessage({ id: "See hotel details" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "See hotel details",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -51,7 +51,7 @@ export default function HotelListing() {
|
||||
<Subtitle type="two">
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "{count, plural, one {# Hotel} other {# Hotels}}",
|
||||
defaultMessage: "{count, plural, one {# Hotel} other {# Hotels}}",
|
||||
},
|
||||
{ count: activeHotels.length }
|
||||
)}
|
||||
@@ -68,7 +68,9 @@ export default function HotelListing() {
|
||||
>
|
||||
<Link href={mapUrl}>
|
||||
<MaterialIcon icon="map" color="CurrentColor" />
|
||||
{intl.formatMessage({ id: "See on map" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "See on map",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
@@ -78,9 +80,12 @@ export default function HotelListing() {
|
||||
{activeHotels.length === 0 ? (
|
||||
<Alert
|
||||
type={AlertTypeEnum.Info}
|
||||
heading={intl.formatMessage({ id: "No matching hotels found" })}
|
||||
heading={intl.formatMessage({
|
||||
defaultMessage: "No matching hotels found",
|
||||
})}
|
||||
text={intl.formatMessage({
|
||||
id: "It looks like no hotels match your filters. Try adjusting your search to find the perfect stay.",
|
||||
defaultMessage:
|
||||
"It looks like no hotels match your filters. Try adjusting your search to find the perfect stay.",
|
||||
})}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -55,7 +55,9 @@ export default function HotelMapCard({
|
||||
variant="icon"
|
||||
className={styles.closeButton}
|
||||
onClick={handleClose}
|
||||
aria-label={intl.formatMessage({ id: "Close" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Close",
|
||||
})}
|
||||
>
|
||||
<MaterialIcon
|
||||
icon="close"
|
||||
@@ -120,7 +122,9 @@ export default function HotelMapCard({
|
||||
size="small"
|
||||
>
|
||||
<Link href={url}>
|
||||
{intl.formatMessage({ id: "See hotel information" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "See hotel information",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -111,7 +111,15 @@ export default function DynamicMap({
|
||||
)}
|
||||
ref={ref}
|
||||
>
|
||||
<ErrorBoundary fallback={<h2>Unable to display map</h2>}>
|
||||
<ErrorBoundary
|
||||
fallback={
|
||||
<h2>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Unable to display map",
|
||||
})}
|
||||
</h2>
|
||||
}
|
||||
>
|
||||
<Map {...mapOptions}>{children}</Map>
|
||||
</ErrorBoundary>
|
||||
<div className={styles.ctaButtons}>
|
||||
@@ -125,7 +133,11 @@ export default function DynamicMap({
|
||||
onClick={onClose}
|
||||
>
|
||||
<MaterialIcon icon="close" color="CurrentColor" />
|
||||
<span>{intl.formatMessage({ id: "Close the map" })}</span>
|
||||
<span>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Close the map",
|
||||
})}
|
||||
</span>
|
||||
</Button>
|
||||
)}
|
||||
<div className={styles.zoomButtons}>
|
||||
@@ -136,7 +148,9 @@ export default function DynamicMap({
|
||||
size="small"
|
||||
className={styles.zoomButton}
|
||||
onClick={zoomIn}
|
||||
aria-label={intl.formatMessage({ id: "Zoom out" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Zoom out",
|
||||
})}
|
||||
>
|
||||
<MaterialIcon icon="add" color="CurrentColor" size={20} />
|
||||
</Button>
|
||||
@@ -147,7 +161,9 @@ export default function DynamicMap({
|
||||
size="small"
|
||||
className={styles.zoomButton}
|
||||
onClick={zoomOut}
|
||||
aria-label={intl.formatMessage({ id: "Zoom in" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Zoom in",
|
||||
})}
|
||||
>
|
||||
<MaterialIcon icon="remove" color="CurrentColor" size={20} />
|
||||
</Button>
|
||||
|
||||
@@ -146,7 +146,9 @@ export default function Map({
|
||||
style={
|
||||
{ "--destination-map-height": mapHeight } as React.CSSProperties
|
||||
}
|
||||
aria-label={intl.formatMessage({ id: "Map view" })}
|
||||
aria-label={intl.formatMessage({
|
||||
defaultMessage: "Map view",
|
||||
})}
|
||||
>
|
||||
<div className={styles.mobileNavigation}>
|
||||
<Button
|
||||
@@ -160,7 +162,9 @@ export default function Map({
|
||||
size={20}
|
||||
color="CurrentColor"
|
||||
/>
|
||||
{intl.formatMessage({ id: "Back" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Back",
|
||||
})}
|
||||
</Button>
|
||||
<DestinationFilterAndSort
|
||||
listType={pageType === "city" ? "hotel" : "city"}
|
||||
|
||||
@@ -45,7 +45,10 @@ export default function DestinationPageSidepeek({
|
||||
size="small"
|
||||
wrapping
|
||||
>
|
||||
{buttonText || intl.formatMessage({ id: "Read more" })}
|
||||
{buttonText ||
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Read more",
|
||||
})}
|
||||
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
||||
</Button>
|
||||
<SidePeek
|
||||
|
||||
@@ -39,7 +39,9 @@ export default function MapButton({ className = "" }: MapButtonProps) {
|
||||
>
|
||||
<Link href={mapUrl} scroll={true}>
|
||||
<MaterialIcon icon="map" color="CurrentColor" />
|
||||
{intl.formatMessage({ id: "See on map" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "See on map",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
)
|
||||
|
||||
@@ -32,8 +32,12 @@ export default async function DestinationStaticMap({
|
||||
}: StaticMapProps) {
|
||||
const intl = await getIntl()
|
||||
const altText = city
|
||||
? intl.formatMessage({ id: "Map of the city" })
|
||||
: intl.formatMessage({ id: "Map of the country" })
|
||||
? intl.formatMessage({
|
||||
defaultMessage: "Map of the city",
|
||||
})
|
||||
: intl.formatMessage({
|
||||
defaultMessage: "Map of the country",
|
||||
})
|
||||
const coordinates = location
|
||||
? { lat: location.latitude, lng: location.longitude }
|
||||
: undefined
|
||||
|
||||
@@ -65,12 +65,16 @@ export default function TopImages({ images, destinationName }: TopImageProps) {
|
||||
onClick={() => setLightboxState({ open: true, activeIndex: 0 })}
|
||||
className={styles.seeAllButton}
|
||||
>
|
||||
{intl.formatMessage({ id: "See all photos" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "See all photos",
|
||||
})}
|
||||
</Button>
|
||||
<Lightbox
|
||||
images={lightboxImages}
|
||||
dialogTitle={intl.formatMessage(
|
||||
{ id: "{title} - Image gallery" },
|
||||
{
|
||||
defaultMessage: "{title} - Image gallery",
|
||||
},
|
||||
{ title: destinationName }
|
||||
)}
|
||||
isOpen={lightboxState.open}
|
||||
|
||||
@@ -18,15 +18,24 @@ export function getHeadingText(
|
||||
|
||||
if (facilityFilter) {
|
||||
return intl.formatMessage(
|
||||
{ id: "Hotels with {filter} in {location}" },
|
||||
{
|
||||
defaultMessage: "Hotels with {filter} in {location}",
|
||||
},
|
||||
{ location, filter: facilityFilter.name }
|
||||
)
|
||||
} else if (surroudingsFilter) {
|
||||
return intl.formatMessage(
|
||||
{ id: "Hotels near {filter} in {location}" },
|
||||
{
|
||||
defaultMessage: "Hotels near {filter} in {location}",
|
||||
},
|
||||
{ location, filter: surroudingsFilter.name }
|
||||
)
|
||||
}
|
||||
}
|
||||
return intl.formatMessage({ id: "Hotels in {location}" }, { location })
|
||||
return intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Hotels in {location}",
|
||||
},
|
||||
{ location }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,11 @@ export default async function AmenitiesList({
|
||||
return (
|
||||
<section className={styles.amenitiesContainer}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<p>{intl.formatMessage({ id: "At the hotel" })}</p>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "At the hotel",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<div className={styles.amenityItemList}>
|
||||
{facilities.map((facility) => {
|
||||
@@ -52,7 +56,9 @@ export default async function AmenitiesList({
|
||||
weight="bold"
|
||||
className={styles.showAllAmenities}
|
||||
>
|
||||
{intl.formatMessage({ id: "See all amenities" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "See all amenities",
|
||||
})}
|
||||
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
@@ -51,10 +51,14 @@ export default async function Facilities({
|
||||
case FacilityCardButtonText.MEETINGS:
|
||||
case FacilityCardButtonText.RESTAURANT:
|
||||
case FacilityCardButtonText.WELLNESS:
|
||||
return intl.formatMessage({ id: "Read more" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Read more",
|
||||
})
|
||||
default:
|
||||
console.warn(`Unsupported option given: ${text}`)
|
||||
return intl.formatMessage({ id: "Read more" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Read more",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@ export default async function IntroSection({
|
||||
const { streetAddress, city } = address
|
||||
const { distanceToCentre } = location
|
||||
const formattedDistanceText = intl.formatMessage(
|
||||
{ id: "{number} km to city center" },
|
||||
{
|
||||
defaultMessage: "{number} km to city center",
|
||||
},
|
||||
{ number: getSingleDecimal(distanceToCentre / 1000) }
|
||||
)
|
||||
|
||||
@@ -32,7 +34,9 @@ export default async function IntroSection({
|
||||
)
|
||||
const formattedTripAdvisorText = hasTripAdvisorData
|
||||
? intl.formatMessage(
|
||||
{ id: "{rating} ({count} reviews on Tripadvisor)" },
|
||||
{
|
||||
defaultMessage: "{rating} ({count} reviews on Tripadvisor)",
|
||||
},
|
||||
{ rating: tripAdvisor.rating, count: tripAdvisor.numberOfReviews }
|
||||
)
|
||||
: ""
|
||||
@@ -43,7 +47,9 @@ export default async function IntroSection({
|
||||
<div className={styles.titleContainer}>
|
||||
<Typography variant="Title/Decorative/lg">
|
||||
<span className={styles.script}>
|
||||
{intl.formatMessage({ id: "Welcome to" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Welcome to",
|
||||
})}
|
||||
</span>
|
||||
</Typography>
|
||||
<Typography variant="Title/lg">
|
||||
@@ -72,7 +78,9 @@ export default async function IntroSection({
|
||||
href={`#s-${SidepeekSlugs.about}`}
|
||||
scroll={false}
|
||||
>
|
||||
{intl.formatMessage({ id: "Read more" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Read more",
|
||||
})}
|
||||
<MaterialIcon
|
||||
icon="chevron_right"
|
||||
size={20}
|
||||
|
||||
@@ -84,28 +84,46 @@ export default function Sidebar({
|
||||
}, 200)
|
||||
}
|
||||
|
||||
const viewAsMapMsg = intl.formatMessage({ id: "View as map" })
|
||||
const viewAsListMsg = intl.formatMessage({ id: "View as list" })
|
||||
const viewAsMapMsg = intl.formatMessage({
|
||||
defaultMessage: "View as map",
|
||||
})
|
||||
const viewAsListMsg = intl.formatMessage({
|
||||
defaultMessage: "View as list",
|
||||
})
|
||||
|
||||
function translatePOIGroup(group: PointOfInterestGroupEnum) {
|
||||
switch (group) {
|
||||
case PointOfInterestGroupEnum.PUBLIC_TRANSPORT:
|
||||
return intl.formatMessage({ id: "Public transport" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Public transport",
|
||||
})
|
||||
case PointOfInterestGroupEnum.ATTRACTIONS:
|
||||
return intl.formatMessage({ id: "Attractions" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Attractions",
|
||||
})
|
||||
case PointOfInterestGroupEnum.BUSINESS:
|
||||
return intl.formatMessage({ id: "Business" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Business",
|
||||
})
|
||||
case PointOfInterestGroupEnum.LOCATION:
|
||||
return intl.formatMessage({ id: "Location" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Location",
|
||||
})
|
||||
case PointOfInterestGroupEnum.PARKING:
|
||||
return intl.formatMessage({ id: "Parking" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Parking",
|
||||
})
|
||||
case PointOfInterestGroupEnum.SHOPPING_DINING:
|
||||
return intl.formatMessage({ id: "Shopping & Dining" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Shopping & Dining",
|
||||
})
|
||||
default:
|
||||
const option: never = group
|
||||
console.warn(`Unsupported group given: ${option}`)
|
||||
|
||||
return intl.formatMessage({ id: "N/A" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "N/A",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +149,9 @@ export default function Sidebar({
|
||||
<div className={styles.sidebarContent}>
|
||||
<Title as="h4" level="h2" textTransform="regular">
|
||||
{intl.formatMessage(
|
||||
{ id: "Things nearby {hotelName}" },
|
||||
{
|
||||
defaultMessage: "Things nearby {hotelName}",
|
||||
},
|
||||
{ hotelName }
|
||||
)}
|
||||
</Title>
|
||||
@@ -163,7 +183,9 @@ export default function Sidebar({
|
||||
<span>{poi.name}</span>
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{ id: "{distanceInKm} km" },
|
||||
{
|
||||
defaultMessage: "{distanceInKm} km",
|
||||
},
|
||||
{
|
||||
distanceInKm: poi.distance,
|
||||
}
|
||||
|
||||
@@ -94,7 +94,11 @@ export default function DynamicMap({
|
||||
onClick={handleClose}
|
||||
>
|
||||
<MaterialIcon icon="close" color="CurrentColor" />
|
||||
<span>{intl.formatMessage({ id: "Close the map" })}</span>
|
||||
<span>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Close the map",
|
||||
})}
|
||||
</span>
|
||||
</Button>
|
||||
)
|
||||
|
||||
@@ -109,7 +113,9 @@ export default function DynamicMap({
|
||||
className={styles.dynamicMap}
|
||||
style={{ "--hotel-map-height": mapHeight } as React.CSSProperties}
|
||||
aria-label={intl.formatMessage(
|
||||
{ id: "Things nearby {hotelName}" },
|
||||
{
|
||||
defaultMessage: "Things nearby {hotelName}",
|
||||
},
|
||||
{ hotelName }
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -34,7 +34,9 @@ export default function MapCard({ hotelName, pois }: MapCardProps) {
|
||||
textTransform="uppercase"
|
||||
textAlign="center"
|
||||
>
|
||||
{intl.formatMessage({ id: "Nearby" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Nearby",
|
||||
})}
|
||||
</Caption>
|
||||
<Title
|
||||
color="burgundy"
|
||||
@@ -57,7 +59,9 @@ export default function MapCard({ hotelName, pois }: MapCardProps) {
|
||||
<Body color="black">{poi.name}</Body>
|
||||
<Caption>
|
||||
{intl.formatMessage(
|
||||
{ id: "{distanceInKm} km" },
|
||||
{
|
||||
defaultMessage: "{distanceInKm} km",
|
||||
},
|
||||
{ distanceInKm: poi.distance }
|
||||
)}
|
||||
</Caption>
|
||||
@@ -68,7 +72,9 @@ export default function MapCard({ hotelName, pois }: MapCardProps) {
|
||||
{mapUrl ? (
|
||||
<Button theme="base" intent="secondary" size="small" fullWidth asChild>
|
||||
<Link href={mapUrl} scroll={true} onClick={trackHotelMapClick}>
|
||||
{intl.formatMessage({ id: "Explore nearby" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Explore nearby",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
@@ -41,7 +41,11 @@ export default function MobileMapToggle() {
|
||||
color={!isMapView ? "Icon/Inverted" : "Icon/Accent"}
|
||||
/>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span>{intl.formatMessage({ id: "Hotel" })}</span>
|
||||
<span>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Hotel",
|
||||
})}
|
||||
</span>
|
||||
</Typography>
|
||||
</span>
|
||||
<span
|
||||
@@ -58,7 +62,11 @@ export default function MobileMapToggle() {
|
||||
color={isMapView ? "Icon/Inverted" : "Icon/Interactive/Accent"}
|
||||
/>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span>{intl.formatMessage({ id: "Map" })}</span>
|
||||
<span>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Map",
|
||||
})}
|
||||
</span>
|
||||
</Typography>
|
||||
</Link>
|
||||
</span>
|
||||
|
||||
@@ -34,7 +34,9 @@ export default async function StaticMap({
|
||||
height={mapHeight}
|
||||
zoomLevel={zoomLevel}
|
||||
altText={intl.formatMessage(
|
||||
{ id: "Map of {hotelName}" },
|
||||
{
|
||||
defaultMessage: "Map of {hotelName}",
|
||||
},
|
||||
{ hotelName }
|
||||
)}
|
||||
mapId={mapId}
|
||||
|
||||
@@ -44,12 +44,16 @@ export default function PreviewImages({
|
||||
onClick={() => setLightboxIsOpen(true)}
|
||||
className={styles.seeAllButton}
|
||||
>
|
||||
{intl.formatMessage({ id: "See all photos" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "See all photos",
|
||||
})}
|
||||
</Button>
|
||||
<Lightbox
|
||||
images={lightboxImages}
|
||||
dialogTitle={intl.formatMessage(
|
||||
{ id: "{title} - Image gallery" },
|
||||
{
|
||||
defaultMessage: "{title} - Image gallery",
|
||||
},
|
||||
{ title: hotelName }
|
||||
)}
|
||||
isOpen={lightboxIsOpen}
|
||||
|
||||
@@ -34,7 +34,9 @@ export function RoomCard({ room }: RoomCardProps) {
|
||||
<ImageGallery
|
||||
images={galleryImages}
|
||||
title={intl.formatMessage(
|
||||
{ id: "{title} - Image gallery" },
|
||||
{
|
||||
defaultMessage: "{title} - Image gallery",
|
||||
},
|
||||
{ title: name }
|
||||
)}
|
||||
fill
|
||||
@@ -55,7 +57,8 @@ export function RoomCard({ room }: RoomCardProps) {
|
||||
<Body color="grey">
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "{size} ({max, plural, one {{range} guest} other {{range} guests}})",
|
||||
defaultMessage:
|
||||
"{size} ({max, plural, one {{range} guest} other {{range} guests}})",
|
||||
},
|
||||
{
|
||||
size,
|
||||
@@ -67,7 +70,9 @@ export function RoomCard({ room }: RoomCardProps) {
|
||||
</div>
|
||||
<Button intent="text" type="button" size="medium" theme="base" asChild>
|
||||
<Link scroll={false} href={`#s-room-${getRoomNameAsParam(name)}`}>
|
||||
{intl.formatMessage({ id: "See room details" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "See room details",
|
||||
})}
|
||||
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
@@ -38,7 +38,11 @@ export function Rooms({ rooms, preamble }: RoomsProps) {
|
||||
<div ref={scrollRef} className={styles.scrollRef}></div>
|
||||
<div className={styles.sectionHeader}>
|
||||
<Typography variant="Title/md" className={styles.heading}>
|
||||
<h2>{intl.formatMessage({ id: "Rooms" })}</h2>
|
||||
<h2>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Rooms",
|
||||
})}
|
||||
</h2>
|
||||
</Typography>
|
||||
{preamble && (
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
|
||||
@@ -31,20 +31,26 @@ export default async function ContactInformation({
|
||||
<div className={styles.wrapper}>
|
||||
<Subtitle color="burgundy" asChild>
|
||||
<Title level="h3">
|
||||
{intl.formatMessage({ id: "Practical information" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Practical information",
|
||||
})}
|
||||
</Title>
|
||||
</Subtitle>
|
||||
<div className={styles.information}>
|
||||
<div className={styles.address}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({ id: "Address" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Address",
|
||||
})}
|
||||
</Body>
|
||||
<Body color="uiTextHighContrast">{hotelAddress.streetAddress}</Body>
|
||||
<Body color="uiTextHighContrast">{hotelAddress.city}</Body>
|
||||
</div>
|
||||
<div className={styles.drivingDirections}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({ id: "Driving directions" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Driving directions",
|
||||
})}
|
||||
</Body>
|
||||
<Link
|
||||
href={directionsUrl}
|
||||
@@ -52,12 +58,16 @@ export default async function ContactInformation({
|
||||
color="peach80"
|
||||
textDecoration="underline"
|
||||
>
|
||||
{intl.formatMessage({ id: "Google Maps" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Google Maps",
|
||||
})}
|
||||
</Link>
|
||||
</div>
|
||||
<div className={styles.contact}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({ id: "Contact us" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Contact us",
|
||||
})}
|
||||
</Body>
|
||||
<Body>
|
||||
<Link
|
||||
@@ -71,14 +81,16 @@ export default async function ContactInformation({
|
||||
{hotelAddress.country === Country.Finland ? (
|
||||
<Caption>
|
||||
{intl.formatMessage({
|
||||
id: "Price 0,16 €/min + local call charges",
|
||||
defaultMessage: "Price 0,16 €/min + local call charges",
|
||||
})}
|
||||
</Caption>
|
||||
) : null}
|
||||
</div>
|
||||
<div className={styles.socials}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({ id: "Follow us" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Follow us",
|
||||
})}
|
||||
</Body>
|
||||
<div className={styles.socialIcons}>
|
||||
{socials.instagram && (
|
||||
@@ -95,7 +107,9 @@ export default async function ContactInformation({
|
||||
</div>
|
||||
<div className={styles.email}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({ id: "Email" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Email",
|
||||
})}
|
||||
</Body>
|
||||
<Link
|
||||
href={`mailto:${contact.email}`}
|
||||
@@ -110,12 +124,16 @@ export default async function ContactInformation({
|
||||
<Image
|
||||
height={38}
|
||||
width={38}
|
||||
alt={intl.formatMessage({ id: "Nordic Swan Ecolabel" })}
|
||||
alt={intl.formatMessage({
|
||||
defaultMessage: "Nordic Swan Ecolabel",
|
||||
})}
|
||||
src={`/_static/img/icons/swan-eco/swan_eco_dark_${lang}.png`}
|
||||
/>
|
||||
<div>
|
||||
<Caption color="uiTextPlaceholder">
|
||||
{intl.formatMessage({ id: "Nordic Swan Ecolabel" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Nordic Swan Ecolabel",
|
||||
})}
|
||||
</Caption>
|
||||
<Caption color="uiTextPlaceholder">
|
||||
{ecoLabels.svanenEcoLabelCertificateNumber}
|
||||
|
||||
@@ -24,7 +24,9 @@ export default async function AboutTheHotelSidePeek({
|
||||
return (
|
||||
<SidePeek
|
||||
contentKey={SidepeekSlugs.about}
|
||||
title={intl.formatMessage({ id: "About the hotel" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "About the hotel",
|
||||
})}
|
||||
>
|
||||
<section className={styles.wrapper}>
|
||||
<ContactInformation
|
||||
|
||||
@@ -18,7 +18,9 @@ export default async function ActivitiesSidePeek({
|
||||
return (
|
||||
<SidePeek
|
||||
contentKey={sidepeekSlug}
|
||||
title={intl.formatMessage({ id: "Activities" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Activities",
|
||||
})}
|
||||
>
|
||||
<Preamble>{preamble}</Preamble>
|
||||
<div className={styles.buttonContainer}>
|
||||
|
||||
@@ -18,7 +18,9 @@ export default async function AccessibilityAmenity({
|
||||
|
||||
return (
|
||||
<AccordionItem
|
||||
title={intl.formatMessage({ id: "Accessibility" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Accessibility",
|
||||
})}
|
||||
iconName={IconName.Accessibility}
|
||||
variant="sidepeek"
|
||||
trackingId="amenities:accessibility"
|
||||
@@ -36,7 +38,9 @@ export default async function AccessibilityAmenity({
|
||||
typography="Body/Paragraph/mdBold"
|
||||
appendToCurrentPath
|
||||
>
|
||||
{intl.formatMessage({ id: "About accessibility" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "About accessibility",
|
||||
})}
|
||||
|
||||
<MaterialIcon icon="arrow_forward" color="CurrentColor" />
|
||||
</ButtonLink>
|
||||
|
||||
@@ -16,18 +16,26 @@ export default async function BreakfastAmenity({
|
||||
|
||||
const accordionContent =
|
||||
hotelType === HotelTypeEnum.ScandicGo ? (
|
||||
<Body>{intl.formatMessage({ id: "All-day breakfast" })}</Body>
|
||||
<Body>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "All-day breakfast",
|
||||
})}
|
||||
</Body>
|
||||
) : (
|
||||
<OpeningHours
|
||||
openingHours={openingHours!}
|
||||
alternateOpeningHours={alternateOpeningHours!}
|
||||
heading={intl.formatMessage({ id: "Opening hours" })}
|
||||
heading={intl.formatMessage({
|
||||
defaultMessage: "Opening hours",
|
||||
})}
|
||||
/>
|
||||
)
|
||||
|
||||
return (
|
||||
<AccordionItem
|
||||
title={intl.formatMessage({ id: "Breakfast" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Breakfast",
|
||||
})}
|
||||
iconName={IconName.CoffeeAlt}
|
||||
variant="sidepeek"
|
||||
trackingId="amenities:breakfast"
|
||||
|
||||
@@ -12,21 +12,33 @@ export default async function CheckInAmenity({
|
||||
const { checkInTime, checkOutTime } = checkInInformation
|
||||
return (
|
||||
<AccordionItem
|
||||
title={`${intl.formatMessage({ id: "Check-in" })}/${intl.formatMessage({ id: "Check-out" })}`}
|
||||
title={`${intl.formatMessage({
|
||||
defaultMessage: "Check-in",
|
||||
})}/${intl.formatMessage({
|
||||
defaultMessage: "Check-out",
|
||||
})}`}
|
||||
iconName={IconName.Business}
|
||||
variant="sidepeek"
|
||||
trackingId="amenities:check-in"
|
||||
>
|
||||
<Body textTransform="bold">{intl.formatMessage({ id: "Times" })}</Body>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Times",
|
||||
})}
|
||||
</Body>
|
||||
<Body color="uiTextHighContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "Check in from: {checkInTime}" },
|
||||
{
|
||||
defaultMessage: "Check in from: {checkInTime}",
|
||||
},
|
||||
{ checkInTime }
|
||||
)}
|
||||
</Body>
|
||||
<Body color="uiTextHighContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "Check out at latest: {checkOutTime}" },
|
||||
{
|
||||
defaultMessage: "Check out at latest: {checkOutTime}",
|
||||
},
|
||||
{ checkOutTime }
|
||||
)}
|
||||
</Body>
|
||||
|
||||
@@ -17,7 +17,9 @@ export default async function ParkingAmenity({
|
||||
|
||||
return (
|
||||
<AccordionItem
|
||||
title={intl.formatMessage({ id: "Parking" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Parking",
|
||||
})}
|
||||
iconName={IconName.Parking}
|
||||
variant="sidepeek"
|
||||
trackingId="amenities:parking"
|
||||
@@ -36,7 +38,9 @@ export default async function ParkingAmenity({
|
||||
typography="Body/Paragraph/mdBold"
|
||||
appendToCurrentPath
|
||||
>
|
||||
{intl.formatMessage({ id: "About parking" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "About parking",
|
||||
})}
|
||||
</ButtonLink>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -45,7 +45,10 @@ export default async function AmenitiesSidePeek({
|
||||
const breakfastDetail = restaurant.openingDetails.find(
|
||||
(details) =>
|
||||
details.openingHours.name === "Breakfast" ||
|
||||
details.openingHours.name === intl.formatMessage({ id: "Breakfast" })
|
||||
details.openingHours.name ===
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Breakfast",
|
||||
})
|
||||
)
|
||||
return breakfastDetail
|
||||
})
|
||||
@@ -54,7 +57,9 @@ export default async function AmenitiesSidePeek({
|
||||
return (
|
||||
<SidePeek
|
||||
contentKey={SidepeekSlugs.amenities}
|
||||
title={intl.formatMessage({ id: "Amenities" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Amenities",
|
||||
})}
|
||||
>
|
||||
<Accordion>
|
||||
<ParkingAmenity
|
||||
|
||||
@@ -23,7 +23,9 @@ export default async function MeetingsAndConferencesSidePeek({
|
||||
const intl = await getIntl()
|
||||
const { seatingText, roomText } = await getConferenceRoomTexts(meetingRooms)
|
||||
|
||||
const fallbackAlt = intl.formatMessage({ id: "Creative spaces for meetings" })
|
||||
const fallbackAlt = intl.formatMessage({
|
||||
defaultMessage: "Creative spaces for meetings",
|
||||
})
|
||||
|
||||
const primaryImage = meetingFacilities?.heroImages[0]?.imageSizes.medium
|
||||
const primaryAltText =
|
||||
@@ -36,12 +38,16 @@ export default async function MeetingsAndConferencesSidePeek({
|
||||
return (
|
||||
<SidePeek
|
||||
contentKey={SidepeekSlugs.meetings}
|
||||
title={intl.formatMessage({ id: "Meetings & Conferences" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Meetings & Conferences",
|
||||
})}
|
||||
>
|
||||
<div className={styles.wrapper}>
|
||||
<Subtitle color="burgundy" asChild>
|
||||
<Title level="h3">
|
||||
{intl.formatMessage({ id: "Creative spaces for meetings" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Creative spaces for meetings",
|
||||
})}
|
||||
</Title>
|
||||
</Subtitle>
|
||||
{primaryImage && (
|
||||
@@ -84,7 +90,9 @@ export default async function MeetingsAndConferencesSidePeek({
|
||||
color="burgundy"
|
||||
appendToCurrentPath
|
||||
>
|
||||
{intl.formatMessage({ id: "Read more" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Read more",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -28,12 +28,17 @@ export async function getRoomText(roomSizes: number[]) {
|
||||
|
||||
let roomText
|
||||
if (largestRoom === smallestRoom) {
|
||||
roomText = intl.formatMessage({ id: "{value} m²" }, { value: largestRoom })
|
||||
roomText = intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{value} m²",
|
||||
},
|
||||
{ value: largestRoom }
|
||||
)
|
||||
} else if (smallestRoom != null && largestRoom) {
|
||||
{
|
||||
roomText = intl.formatMessage(
|
||||
{
|
||||
id: "{smallest}–{largest} m²",
|
||||
defaultMessage: "{smallest}–{largest} m²",
|
||||
},
|
||||
{ largest: largestRoom, smallest: smallestRoom }
|
||||
)
|
||||
@@ -50,14 +55,16 @@ export async function getSeatingText(roomSeating: number[]) {
|
||||
let seatingText
|
||||
if (biggestSeating === smallestSeating) {
|
||||
seatingText = intl.formatMessage(
|
||||
{ id: "{value, plural, one {# guest} other {# guests}}" },
|
||||
{
|
||||
defaultMessage: "{value, plural, one {# guest} other {# guests}}",
|
||||
},
|
||||
{ value: biggestSeating }
|
||||
)
|
||||
} else if (smallestSeating != null && biggestSeating) {
|
||||
{
|
||||
seatingText = intl.formatMessage(
|
||||
{
|
||||
id: "{lowest}–{highest} guests",
|
||||
defaultMessage: "{lowest}–{highest} guests",
|
||||
},
|
||||
{ highest: biggestSeating, lowest: smallestSeating }
|
||||
)
|
||||
|
||||
@@ -55,7 +55,9 @@ export default async function RestaurantBarItem({
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h4 className={styles.text}>
|
||||
{intl.formatMessage({ id: "Opening hours" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Opening hours",
|
||||
})}
|
||||
</h4>
|
||||
</Typography>
|
||||
{openingDetails.map((details) => (
|
||||
@@ -71,7 +73,9 @@ export default async function RestaurantBarItem({
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h4 className={styles.text}>
|
||||
{intl.formatMessage({ id: "Menus" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Menus",
|
||||
})}
|
||||
</h4>
|
||||
</Typography>
|
||||
<ul className={styles.menuList}>
|
||||
@@ -111,8 +115,12 @@ export default async function RestaurantBarItem({
|
||||
trackingParams={{ restaurantName: name }}
|
||||
>
|
||||
{restaurantPage && !mainBody?.length
|
||||
? intl.formatMessage({ id: "Read more" })
|
||||
: intl.formatMessage({ id: "Book a table online" })}
|
||||
? intl.formatMessage({
|
||||
defaultMessage: "Read more",
|
||||
})
|
||||
: intl.formatMessage({
|
||||
defaultMessage: "Book a table online",
|
||||
})}
|
||||
</ButtonLink>
|
||||
) : null}
|
||||
{restaurantPage && mainBody?.length ? (
|
||||
@@ -124,7 +132,12 @@ export default async function RestaurantBarItem({
|
||||
href={`/${restaurant.nameInUrl}`}
|
||||
appendToCurrentPath
|
||||
>
|
||||
{intl.formatMessage({ id: "Discover {name}" }, { name: name })}
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Discover {name}",
|
||||
},
|
||||
{ name: name }
|
||||
)}
|
||||
</ButtonLink>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,9 @@ export default async function RestaurantBarSidePeek({
|
||||
return (
|
||||
<SidePeek
|
||||
contentKey={SidepeekSlugs.restaurant}
|
||||
title={intl.formatMessage({ id: "Restaurant & Bar" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Restaurant & Bar",
|
||||
})}
|
||||
>
|
||||
<div className={styles.content}>
|
||||
{restaurants.map((restaurant) => (
|
||||
|
||||
@@ -51,24 +51,28 @@ export default async function RoomSidePeek({
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "Max. {max, plural, one {{range} guest} other {{range} guests}}",
|
||||
defaultMessage:
|
||||
"Max. {max, plural, one {{range} guest} other {{range} guests}}",
|
||||
},
|
||||
{
|
||||
max: totalOccupancy.max,
|
||||
range: totalOccupancy.range,
|
||||
}
|
||||
)}
|
||||
.{" "}
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
{". "}
|
||||
{roomSize.min === roomSize.max
|
||||
? intl.formatMessage(
|
||||
{ id: "{roomSize} m²" },
|
||||
{
|
||||
defaultMessage: "{roomSize} m²",
|
||||
},
|
||||
{
|
||||
roomSize: roomSize.min,
|
||||
}
|
||||
)
|
||||
: intl.formatMessage(
|
||||
{
|
||||
id: "{roomSizeMin}–{roomSizeMax} m²",
|
||||
defaultMessage: "{roomSizeMin}–{roomSizeMax} m²",
|
||||
},
|
||||
{
|
||||
roomSizeMin: roomSize.min,
|
||||
@@ -92,7 +96,11 @@ export default async function RoomSidePeek({
|
||||
|
||||
<div className={styles.innerContent}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h3>{intl.formatMessage({ id: "Room amenities" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Room amenities",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<ul className={styles.facilityList}>
|
||||
{room.roomFacilities
|
||||
@@ -125,10 +133,18 @@ export default async function RoomSidePeek({
|
||||
<div className={styles.innerContent}>
|
||||
<div className={styles.bedOptions}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h3>{intl.formatMessage({ id: "Bed options" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Bed options",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{intl.formatMessage({ id: "Based on availability" })}</p>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Based on availability",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<ul className={styles.bedOptions}>
|
||||
@@ -154,7 +170,9 @@ export default async function RoomSidePeek({
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button theme="base" intent="primary" asChild>
|
||||
<Link href={selectRateURL}>
|
||||
{intl.formatMessage({ id: "Prices & availability" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Prices & availability",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -33,14 +33,21 @@ export default async function Facility({ data }: FacilityProps) {
|
||||
</Subtitle>
|
||||
<div>
|
||||
<Subtitle type="two" color="uiTextHighContrast">
|
||||
{intl.formatMessage({ id: "Opening hours" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Opening hours",
|
||||
})}
|
||||
</Subtitle>
|
||||
<div className={styles.openingHours}>
|
||||
<Body color="uiTextHighContrast">
|
||||
{ordinaryOpeningTimes.alwaysOpen
|
||||
? intl.formatMessage({ id: "Monday–Friday: Always open" })
|
||||
? intl.formatMessage({
|
||||
defaultMessage: "Monday–Friday: Always open",
|
||||
})
|
||||
: intl.formatMessage(
|
||||
{ id: "Monday–Friday: {openingTime}–{closingTime}" },
|
||||
{
|
||||
defaultMessage:
|
||||
"Monday–Friday: {openingTime}–{closingTime}",
|
||||
},
|
||||
{
|
||||
openingTime: ordinaryOpeningTimes.openingTime,
|
||||
closingTime: ordinaryOpeningTimes.closingTime,
|
||||
@@ -49,9 +56,14 @@ export default async function Facility({ data }: FacilityProps) {
|
||||
</Body>
|
||||
<Body color="uiTextHighContrast">
|
||||
{weekendOpeningTimes.alwaysOpen
|
||||
? intl.formatMessage({ id: "Saturday–Sunday: Always open" })
|
||||
? intl.formatMessage({
|
||||
defaultMessage: "Saturday–Sunday: Always open",
|
||||
})
|
||||
: intl.formatMessage(
|
||||
{ id: "Saturday–Sunday: {openingTime}–{closingTime}" },
|
||||
{
|
||||
defaultMessage:
|
||||
"Saturday–Sunday: {openingTime}–{closingTime}",
|
||||
},
|
||||
{
|
||||
openingTime: weekendOpeningTimes.openingTime,
|
||||
closingTime: weekendOpeningTimes.closingTime,
|
||||
|
||||
@@ -20,7 +20,9 @@ export default async function WellnessAndExerciseSidePeek({
|
||||
return (
|
||||
<SidePeek
|
||||
contentKey={SidepeekSlugs.wellness}
|
||||
title={intl.formatMessage({ id: "Gym & Wellness" })}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Gym & Wellness",
|
||||
})}
|
||||
>
|
||||
<div className={styles.wrapper}>
|
||||
{healthFacilities.map((facility) => (
|
||||
@@ -44,7 +46,9 @@ export default async function WellnessAndExerciseSidePeek({
|
||||
color="burgundy"
|
||||
appendToCurrentPath
|
||||
>
|
||||
{intl.formatMessage({ id: "Show Gym & Wellness" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Show Gym & Wellness",
|
||||
})}
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -40,11 +40,19 @@ export default function TabNavigation({
|
||||
const tabLinks: { hash: HotelHashValues; text: string }[] = [
|
||||
{
|
||||
hash: HotelHashValues.overview,
|
||||
text: tabValues?.overview || intl.formatMessage({ id: "Overview" }),
|
||||
text:
|
||||
tabValues?.overview ||
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Overview",
|
||||
}),
|
||||
},
|
||||
{
|
||||
hash: HotelHashValues.rooms,
|
||||
text: tabValues?.rooms || intl.formatMessage({ id: "Rooms" }),
|
||||
text:
|
||||
tabValues?.rooms ||
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Rooms",
|
||||
}),
|
||||
},
|
||||
...(hasRestaurants
|
||||
? [
|
||||
@@ -52,7 +60,9 @@ export default function TabNavigation({
|
||||
hash: HotelHashValues.restaurant,
|
||||
text:
|
||||
tabValues?.restaurant_bar ||
|
||||
intl.formatMessage({ id: "Restaurant & Bar" }),
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Restaurant & Bar",
|
||||
}),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
@@ -62,7 +72,9 @@ export default function TabNavigation({
|
||||
hash: HotelHashValues.meetings,
|
||||
text:
|
||||
tabValues?.conferences_meetings ||
|
||||
intl.formatMessage({ id: "Meetings & Conferences" }),
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Meetings & Conferences",
|
||||
}),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
@@ -72,7 +84,9 @@ export default function TabNavigation({
|
||||
hash: HotelHashValues.wellness,
|
||||
text:
|
||||
tabValues?.health_wellness ||
|
||||
intl.formatMessage({ id: "Gym & Wellness" }),
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Gym & Wellness",
|
||||
}),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
@@ -81,7 +95,10 @@ export default function TabNavigation({
|
||||
{
|
||||
hash: HotelHashValues.activities,
|
||||
text:
|
||||
tabValues?.activities || intl.formatMessage({ id: "Activities" }),
|
||||
tabValues?.activities ||
|
||||
intl.formatMessage({
|
||||
defaultMessage: "Activities",
|
||||
}),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
@@ -89,7 +106,11 @@ export default function TabNavigation({
|
||||
? [
|
||||
{
|
||||
hash: HotelHashValues.faq,
|
||||
text: tabValues?.faq || intl.formatMessage({ id: "FAQ" }),
|
||||
text:
|
||||
tabValues?.faq ||
|
||||
intl.formatMessage({
|
||||
defaultMessage: "FAQ",
|
||||
}),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
||||
@@ -54,19 +54,33 @@ export function getTrackingHotelData(hotelData: HotelData["hotel"]) {
|
||||
export function translateWellnessType(type: string, intl: IntlShape) {
|
||||
switch (type) {
|
||||
case HealthFacilitiesEnum.Gym:
|
||||
return intl.formatMessage({ id: "Gym" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Gym",
|
||||
})
|
||||
case HealthFacilitiesEnum.IndoorPool:
|
||||
return intl.formatMessage({ id: "Indoor pool" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Indoor pool",
|
||||
})
|
||||
case HealthFacilitiesEnum.Jacuzzi:
|
||||
return intl.formatMessage({ id: "Jacuzzi" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Jacuzzi",
|
||||
})
|
||||
case HealthFacilitiesEnum.OutdoorPool:
|
||||
return intl.formatMessage({ id: "Outdoor pool" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Outdoor pool",
|
||||
})
|
||||
case HealthFacilitiesEnum.Relax:
|
||||
return intl.formatMessage({ id: "Relax" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Relax",
|
||||
})
|
||||
case HealthFacilitiesEnum.Sauna:
|
||||
return intl.formatMessage({ id: "Sauna" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Sauna",
|
||||
})
|
||||
default:
|
||||
console.warn(`Unsupported group given: ${type}`)
|
||||
return intl.formatMessage({ id: "Wellness" })
|
||||
return intl.formatMessage({
|
||||
defaultMessage: "Wellness",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ export default function AccessibilityAdditionalContent({
|
||||
<Body key={groupItem.name} asChild>
|
||||
<li>
|
||||
{groupItem.details
|
||||
? `${groupItem.name}: ${groupItem.details}`
|
||||
? // eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
||||
`${groupItem.name}: ${groupItem.details}`
|
||||
: groupItem.name}
|
||||
</li>
|
||||
</Body>
|
||||
|
||||
@@ -24,7 +24,11 @@ export default async function MeetingsSidebar({
|
||||
<aside className={styles.sidebar}>
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/xs" className={styles.heading}>
|
||||
<h3>{intl.formatMessage({ id: "Contact us" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Contact us",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<div className={styles.contactDetails}>
|
||||
<Link href={`tel:${phoneNumber}`}>{phoneNumber}</Link>
|
||||
@@ -35,7 +39,7 @@ export default async function MeetingsSidebar({
|
||||
>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "Price 0,16 €/min + local call charges",
|
||||
defaultMessage: "Price 0,16 €/min + local call charges",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
|
||||
@@ -19,7 +19,11 @@ export default async function ParkingSidebar({ hotel }: HotelSidebarProps) {
|
||||
<aside className={styles.sidebar}>
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/xs" className={styles.heading}>
|
||||
<h3>{intl.formatMessage({ id: "Address" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Address",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="Body/Paragraph/mdRegular" className={styles.text}>
|
||||
@@ -35,7 +39,11 @@ export default async function ParkingSidebar({ hotel }: HotelSidebarProps) {
|
||||
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/xs" className={styles.heading}>
|
||||
<h3>{intl.formatMessage({ id: "Contact us" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Contact us",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<div className={styles.contactDetails}>
|
||||
<Link href={`tel:${hotel.contactInformation.phoneNumber}`}>
|
||||
@@ -48,7 +56,7 @@ export default async function ParkingSidebar({ hotel }: HotelSidebarProps) {
|
||||
>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "Price 0,16 €/min + local call charges",
|
||||
defaultMessage: "Price 0,16 €/min + local call charges",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
|
||||
@@ -30,7 +30,11 @@ export default async function RestaurantSidebar({
|
||||
{openingDetails.length ? (
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/xs" className={styles.heading}>
|
||||
<h3>{intl.formatMessage({ id: "Opening hours" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Opening hours",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
{openingDetails.map((details) => (
|
||||
<OpeningHours
|
||||
@@ -46,7 +50,9 @@ export default async function RestaurantSidebar({
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button intent="primary" theme="base" asChild>
|
||||
<a href={bookTableUrl}>
|
||||
{intl.formatMessage({ id: "Book a table online" })}
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Book a table online",
|
||||
})}
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
@@ -54,7 +60,11 @@ export default async function RestaurantSidebar({
|
||||
{restaurant.menus.length ? (
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/xs" className={styles.heading}>
|
||||
<h3>{intl.formatMessage({ id: "Menus" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Menus",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<ul className={styles.menuList}>
|
||||
{restaurant.menus.map(({ name, url }) => (
|
||||
@@ -79,11 +89,16 @@ export default async function RestaurantSidebar({
|
||||
) : null}
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/xs" className={styles.heading}>
|
||||
<h3>{intl.formatMessage({ id: "Address" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Address",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular" className={styles.text}>
|
||||
<div>
|
||||
<p>{address.streetAddress}</p>
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
<p>{`${address.zipCode} ${address.city}`}</p>
|
||||
</div>
|
||||
</Typography>
|
||||
@@ -91,7 +106,11 @@ export default async function RestaurantSidebar({
|
||||
{(phoneNumber || email) && (
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/xs" className={styles.heading}>
|
||||
<h3>{intl.formatMessage({ id: "Contact us" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Contact us",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<div className={styles.contactDetails}>
|
||||
{phoneNumber && (
|
||||
@@ -104,7 +123,7 @@ export default async function RestaurantSidebar({
|
||||
>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "Price 0,16 €/min + local call charges",
|
||||
defaultMessage: "Price 0,16 €/min + local call charges",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
|
||||
@@ -21,7 +21,11 @@ export default async function WellnessSidebar({ hotel }: WellnessSidebarProps) {
|
||||
<aside className={styles.sidebar}>
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/xs" className={styles.heading}>
|
||||
<h3>{intl.formatMessage({ id: "Opening hours" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Opening hours",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
{hotel.healthFacilities.map((facility) => (
|
||||
<div key={facility.type}>
|
||||
@@ -36,9 +40,14 @@ export default async function WellnessSidebar({ hotel }: WellnessSidebarProps) {
|
||||
<div>
|
||||
<p>
|
||||
{facility.openingDetails.openingHours.ordinary.alwaysOpen
|
||||
? intl.formatMessage({ id: "Monday–Friday: Always open" })
|
||||
? intl.formatMessage({
|
||||
defaultMessage: "Monday–Friday: Always open",
|
||||
})
|
||||
: intl.formatMessage(
|
||||
{ id: "Monday–Friday: {openingTime}–{closingTime}" },
|
||||
{
|
||||
defaultMessage:
|
||||
"Monday–Friday: {openingTime}–{closingTime}",
|
||||
},
|
||||
{
|
||||
openingTime:
|
||||
facility.openingDetails.openingHours.ordinary
|
||||
@@ -51,9 +60,14 @@ export default async function WellnessSidebar({ hotel }: WellnessSidebarProps) {
|
||||
</p>
|
||||
<p>
|
||||
{facility.openingDetails.openingHours.weekends.alwaysOpen
|
||||
? intl.formatMessage({ id: "Saturday–Sunday: Always open" })
|
||||
? intl.formatMessage({
|
||||
defaultMessage: "Saturday–Sunday: Always open",
|
||||
})
|
||||
: intl.formatMessage(
|
||||
{ id: "Saturday–Sunday: {openingTime}–{closingTime}" },
|
||||
{
|
||||
defaultMessage:
|
||||
"Saturday–Sunday: {openingTime}–{closingTime}",
|
||||
},
|
||||
{
|
||||
openingTime:
|
||||
facility.openingDetails.openingHours.weekends
|
||||
@@ -71,7 +85,11 @@ export default async function WellnessSidebar({ hotel }: WellnessSidebarProps) {
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/xs" className={styles.heading}>
|
||||
<h3>{intl.formatMessage({ id: "Address" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Address",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<div className={styles.contactDetails}>
|
||||
<Typography
|
||||
@@ -91,7 +109,11 @@ export default async function WellnessSidebar({ hotel }: WellnessSidebarProps) {
|
||||
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/xs" className={styles.heading}>
|
||||
<h3>{intl.formatMessage({ id: "Contact us" })}</h3>
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Contact us",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<Link href={`tel:${hotel.contactInformation.phoneNumber}`}>
|
||||
{hotel.contactInformation.phoneNumber}
|
||||
@@ -103,7 +125,7 @@ export default async function WellnessSidebar({ hotel }: WellnessSidebarProps) {
|
||||
>
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "Price 0,16 €/min + local call charges",
|
||||
defaultMessage: "Price 0,16 €/min + local call charges",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user