feat(SW-66, SW-348): search functionality and ui

This commit is contained in:
Simon Emanuelsson
2024-08-28 10:47:57 +02:00
parent b9dbcf7d90
commit af850c90e7
437 changed files with 7663 additions and 9881 deletions

View File

@@ -0,0 +1,39 @@
import { Lang } from "@/constants/languages"
import { dt } from "@/lib/dt"
import Body from "@/components/TempDesignSystem/Text/Body"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import { getMembership } from "@/utils/user"
import type { UserProps } from "@/types/components/myPages/user"
export default async function ExpiringPoints({ user }: UserProps) {
const intl = await getIntl()
const membership = getMembership(user.memberships)
if (!membership || !membership.pointsToExpire) {
// TODO: handle this case?
return null
}
// sv hardcoded to force space on thousands
const formatter = new Intl.NumberFormat(Lang.sv)
const d = dt(membership.pointsExpiryDate)
const dateFormat = getLang() == Lang.fi ? "DD.MM.YYYY" : "YYYY-MM-DD"
return (
<section>
<Body color="white" textTransform="bold" textAlign="center">
{intl.formatMessage(
{ id: "spendable points expiring by" },
{
points: formatter.format(membership.pointsToExpire),
date: d.format(dateFormat),
}
)}
</Body>
</section>
)
}

View File

@@ -0,0 +1,13 @@
.points {
display: grid;
gap: var(--Spacing-x5);
text-wrap: balance;
}
@media screen and (min-width: 768px) {
.points {
grid-auto-flow: column;
row-gap: 0;
column-gap: var(--Spacing-x2);
}
}

View File

@@ -0,0 +1,5 @@
import styles from "./container.module.css"
export default function PointsContainer({ children }: React.PropsWithChildren) {
return <section className={styles.points}>{children}</section>
}

View File

@@ -0,0 +1,71 @@
import Body from "@/components/TempDesignSystem/Text/Body"
import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import styles from "./pointsColumn.module.css"
import type {
NightsColumn,
PointsColumn,
PointsColumnProps,
} from "@/types/components/myPages/points"
export const YourPointsColumn = ({ points }: PointsColumn) =>
PointsColumn({
points,
title: "Your points to spend",
subtitle: "as of today",
})
export const NextLevelPointsColumn = ({ points, subtitle }: PointsColumn) =>
PointsColumn({
points,
title: "Points needed to level up",
subtitle,
})
export const StayOnLevelColumn = ({ points, subtitle }: PointsColumn) =>
PointsColumn({
points,
title: "Points needed to stay on level",
subtitle,
})
export const NextLevelNightsColumn = ({ nights, subtitle }: NightsColumn) =>
PointsColumn({
nights,
title: "Nights needed to level up",
subtitle,
})
async function PointsColumn({
points,
nights,
title,
subtitle,
}: PointsColumnProps) {
const { formatMessage } = await getIntl()
return (
<article className={styles.article}>
<Body
color="white"
textTransform="bold"
textAlign="center"
className={styles.firstRow}
>
{formatMessage({
id: title,
})}
</Body>
<Title color="white" level="h2" textAlign="center">
{points ?? nights ?? "N/A"}
</Title>
{subtitle ? (
<Body color="white" textAlign="center">
{subtitle}
</Body>
) : null}
</article>
)
}

View File

@@ -0,0 +1,9 @@
@media screen and (min-width: 768px) {
.firstRow {
align-content: flex-end;
}
.article {
display: grid;
}
}

View File

@@ -0,0 +1,43 @@
import { MembershipLevelEnum } from "@/constants/membershipLevels"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import { getMembershipLevelObject } from "@/utils/membershipLevel"
import { getMembership } from "@/utils/user"
import PointsContainer from "./Container"
import { NextLevelPointsColumn, YourPointsColumn } from "./PointsColumn"
import { UserProps } from "@/types/components/myPages/user"
export default async function Points({ user }: UserProps) {
const { formatMessage } = await getIntl()
const membership = getMembership(user.memberships)
const nextLevel = getMembershipLevelObject(
membership?.nextLevel as MembershipLevelEnum,
getLang()
)
return (
<PointsContainer>
<YourPointsColumn points={membership?.currentPoints} />
{nextLevel && (
<NextLevelPointsColumn
points={membership?.pointsRequiredToNextlevel}
subtitle={`${formatMessage({ id: "next level:" })} ${nextLevel.name}`}
/>
)}
{/* TODO: Show NextLevelNightsColumn when nightsToTopTier data is correct from Antavo */}
{/* {membership?.nightsToTopTier && (
<NextLevelNightsColumn
nights={membership.nightsToTopTier}
subtitle={
membership.tierExpirationDate &&
`by ${membership.tierExpirationDate}`
}
/>
)} */}
</PointsContainer>
)
}

View File

@@ -0,0 +1,18 @@
import Divider from "@/components/TempDesignSystem/Divider"
import ExpiringPoints from "./ExpiringPoints"
import Points from "./Points"
import styles from "./stats.module.css"
import type { UserProps } from "@/types/components/myPages/user"
export default function Stats({ user }: UserProps) {
return (
<section className={styles.stats}>
<Points user={user} />
<Divider variant="default" color="pale" />
<ExpiringPoints user={user} />
</section>
)
}

View File

@@ -0,0 +1,11 @@
.stats {
align-content: center;
display: grid;
gap: var(--Spacing-x2);
}
@media screen and (min-width: 1367px) {
.stats {
gap: var(--Spacing-x4);
}
}