fix(LOY-430): don't show inactive campaigns * fix(LOY-430): don't show inactive campaigns Approved-by: Chuma Mcphoy (We Ahead)
129 lines
4.0 KiB
TypeScript
129 lines
4.0 KiB
TypeScript
import { cx } from "class-variance-authority"
|
|
|
|
import Table from "@scandic-hotels/design-system/Table"
|
|
import { TextLink } from "@scandic-hotels/design-system/TextLink"
|
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
|
|
|
import { getAllHotelData } from "@/lib/trpc/memoizedRequests"
|
|
|
|
import { getIntl } from "@/i18n"
|
|
|
|
import styles from "./rewardNights.module.css"
|
|
|
|
import type { RewardNight } from "@scandic-hotels/trpc/types/hotel"
|
|
|
|
export async function RewardNights() {
|
|
const intl = await getIntl()
|
|
const hotelData = await getAllHotelData()
|
|
|
|
return (
|
|
<Table intent="striped" variant="content" style={{ textWrap: "balance" }}>
|
|
<Table.THead>
|
|
<Table.TR>
|
|
<Table.TH>
|
|
{intl.formatMessage({
|
|
id: "rewardNights.table.hotel",
|
|
defaultMessage: "Hotel",
|
|
})}
|
|
</Table.TH>
|
|
<Table.TH>
|
|
{intl.formatMessage({
|
|
id: "rewardNights.table.destination",
|
|
defaultMessage: "Destination",
|
|
})}
|
|
</Table.TH>
|
|
<Table.TH>
|
|
{intl.formatMessage({
|
|
id: "common.points",
|
|
defaultMessage: "Points",
|
|
})}
|
|
</Table.TH>
|
|
</Table.TR>
|
|
</Table.THead>
|
|
<Table.TBody>
|
|
{hotelData.map((data) => {
|
|
const { hotel } = data
|
|
const hasCampaign = hasActiveCampaign(hotel.rewardNight.campaign)
|
|
return (
|
|
<Table.TR key={hotel.id}>
|
|
<Table.TD style={{ alignContent: "flex-start" }}>
|
|
<TextLink href={data.url ?? ""}>{hotel.name}</TextLink>
|
|
</Table.TD>
|
|
<Table.TD>
|
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
|
{`${hotel.address.city}, ${hotel.address.country}`}
|
|
{hasCampaign ? (
|
|
<OfferPrice {...hotel.rewardNight.campaign} />
|
|
) : null}
|
|
</Table.TD>
|
|
<Table.TD style={{ alignContent: "flex-start" }}>
|
|
<div className={cx({ [styles.grid]: hasCampaign })}>
|
|
{formatPoints(hotel.rewardNight.points)}
|
|
{hasCampaign ? (
|
|
<Typography
|
|
variant="Body/Paragraph/mdBold"
|
|
className={styles.highlightedText}
|
|
>
|
|
<span>
|
|
{formatPoints(hotel.rewardNight.campaign.points)}
|
|
</span>
|
|
</Typography>
|
|
) : null}
|
|
</div>
|
|
</Table.TD>
|
|
</Table.TR>
|
|
)
|
|
})}
|
|
</Table.TBody>
|
|
</Table>
|
|
)
|
|
}
|
|
interface OfferPriceProps {
|
|
points: number
|
|
start: string
|
|
end: string
|
|
}
|
|
async function OfferPrice(offer: OfferPriceProps) {
|
|
const intl = await getIntl()
|
|
|
|
return (
|
|
<div className={styles.offerPrice}>
|
|
<Typography variant="Body/Paragraph/mdBold">
|
|
<p className={styles.highlightedText}>
|
|
{intl.formatMessage({
|
|
id: "rewardNights.offerPrice",
|
|
defaultMessage: "Offer price",
|
|
})}
|
|
</p>
|
|
</Typography>
|
|
<Typography variant="Label/xsBold">
|
|
<p>
|
|
{intl.formatMessage({
|
|
id: "rewardNights.stayBetween:",
|
|
defaultMessage: "Stay between:",
|
|
})}
|
|
</p>
|
|
</Typography>
|
|
<Typography variant="Label/xsRegular">
|
|
<time>
|
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
|
{formatDate(offer.start)} - {formatDate(offer.end)}
|
|
</time>
|
|
</Typography>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function formatPoints(number: number) {
|
|
const format = new Intl.NumberFormat("fr-FR")
|
|
return format.format(number).replace(/\u202F/g, " ")
|
|
}
|
|
|
|
function formatDate(date?: string) {
|
|
return new Date(date ?? Date.now()).toISOString().split("T")[0]
|
|
}
|
|
|
|
function hasActiveCampaign(campaign: RewardNight["campaign"]) {
|
|
return campaign.points && formatDate(campaign.end) >= formatDate()
|
|
}
|