feat(SW-66, SW-348): search functionality and ui
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
.awardPoints {
|
||||
color: var(--Base-Text-High-contrast);
|
||||
}
|
||||
|
||||
.addition {
|
||||
color: var(--Secondary-Light-On-Surface-Accent);
|
||||
}
|
||||
|
||||
.addition::before {
|
||||
color: var(--Secondary-Light-On-Surface-Accent);
|
||||
content: "+";
|
||||
margin-right: var(--Spacing-x-half);
|
||||
}
|
||||
|
||||
.negation {
|
||||
color: var(--Base-Text-Accent);
|
||||
}
|
||||
|
||||
.negation::before {
|
||||
color: var(--Base-Text-Accent);
|
||||
content: "-";
|
||||
margin-right: var(--Spacing-x-half);
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { cva } from "class-variance-authority"
|
||||
|
||||
import styles from "./awardPoints.module.css"
|
||||
|
||||
export const awardPointsVariants = cva(styles.awardPoints, {
|
||||
variants: {
|
||||
variant: {
|
||||
addition: styles.addition,
|
||||
negation: styles.negation,
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
|
||||
import { awardPointsVariants } from "./awardPointsVariants"
|
||||
|
||||
import type { AwardPointsVariantProps } from "@/types/components/myPages/myPage/earnAndBurn"
|
||||
|
||||
export default function AwardPoints({
|
||||
awardPoints,
|
||||
isCalculated,
|
||||
isExpiringPoints = false,
|
||||
}: {
|
||||
awardPoints: number
|
||||
isCalculated: boolean
|
||||
isExpiringPoints?: boolean
|
||||
}) {
|
||||
let variant: AwardPointsVariantProps["variant"] = null
|
||||
const intl = useIntl()
|
||||
|
||||
if (isCalculated && !isExpiringPoints) {
|
||||
if (awardPoints > 0) {
|
||||
variant = "addition"
|
||||
} else if (awardPoints < 0) {
|
||||
variant = "negation"
|
||||
awardPoints = Math.abs(awardPoints)
|
||||
}
|
||||
}
|
||||
const classNames = awardPointsVariants({
|
||||
variant,
|
||||
})
|
||||
|
||||
// sv hardcoded to force space on thousands
|
||||
const formatter = new Intl.NumberFormat(Lang.sv)
|
||||
return (
|
||||
<Body textTransform="bold" className={classNames}>
|
||||
{isCalculated
|
||||
? formatter.format(awardPoints)
|
||||
: intl.formatMessage({ id: "Points being calculated" })}
|
||||
</Body>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
"use client"
|
||||
|
||||
import { keepPreviousData } from "@tanstack/react-query"
|
||||
import { useState } from "react"
|
||||
|
||||
import { trpc } from "@/lib/trpc/client"
|
||||
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
|
||||
import ClientTable from "./ClientTable"
|
||||
import Pagination from "./Pagination"
|
||||
|
||||
import { Transactions } from "@/types/components/myPages/myPage/earnAndBurn"
|
||||
|
||||
export default function TransactionTable({
|
||||
initialJourneyTransactions,
|
||||
}: {
|
||||
initialJourneyTransactions: {
|
||||
data: { transactions: Transactions }
|
||||
meta: { totalPages: number }
|
||||
}
|
||||
}) {
|
||||
const limit = 5
|
||||
const [page, setPage] = useState(1)
|
||||
const { data, isFetching, isLoading } =
|
||||
trpc.user.transaction.friendTransactions.useQuery(
|
||||
{
|
||||
limit,
|
||||
page,
|
||||
},
|
||||
{
|
||||
// TODO: fix the initial data issues on page load
|
||||
// initialData: initialJourneyTransactions,
|
||||
placeholderData: keepPreviousData,
|
||||
}
|
||||
)
|
||||
|
||||
return isLoading ? (
|
||||
<LoadingSpinner />
|
||||
) : (
|
||||
<>
|
||||
<ClientTable transactions={data?.data.transactions || []} />
|
||||
{data && data.meta.totalPages > 1 ? (
|
||||
<Pagination
|
||||
handlePageChange={setPage}
|
||||
pageCount={data.meta.totalPages}
|
||||
isFetching={isFetching}
|
||||
currentPage={page}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
"use client"
|
||||
|
||||
import { usePathname } from "next/navigation"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { webviews } from "@/constants/routes/webviews"
|
||||
import { dt } from "@/lib/dt"
|
||||
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Table from "@/components/TempDesignSystem/Table"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import AwardPoints from "../../../AwardPoints"
|
||||
|
||||
import type { RowProps } from "@/types/components/myPages/myPage/earnAndBurn"
|
||||
import { Transactions } from "@/types/enums/transactions"
|
||||
|
||||
export default function Row({ transaction }: RowProps) {
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
const pathName = usePathname()
|
||||
const isWebview = webviews.includes(pathName)
|
||||
|
||||
const nightString = `${transaction.nights} ${transaction.nights === 1 ? intl.formatMessage({ id: "night" }) : intl.formatMessage({ id: "nights" })}`
|
||||
|
||||
let description =
|
||||
transaction.hotelName && transaction.city
|
||||
? `${transaction.hotelName}, ${transaction.city} ${nightString}`
|
||||
: `${nightString}`
|
||||
|
||||
switch (transaction.type) {
|
||||
case Transactions.rewardType.stay:
|
||||
case Transactions.rewardType.stayAdj:
|
||||
if (transaction.hotelId === "ORS") {
|
||||
description = intl.formatMessage({ id: "Former Scandic Hotel" })
|
||||
}
|
||||
if (transaction.confirmationNumber === "BALFWD") {
|
||||
description = intl.formatMessage({
|
||||
id: "Points earned prior to May 1, 2021",
|
||||
})
|
||||
}
|
||||
break
|
||||
case Transactions.rewardType.ancillary:
|
||||
description = intl.formatMessage({ id: "Extras to your booking" })
|
||||
break
|
||||
case Transactions.rewardType.enrollment:
|
||||
description = intl.formatMessage({ id: "Sign up bonus" })
|
||||
break
|
||||
case Transactions.rewardType.mastercard_points:
|
||||
description = intl.formatMessage({ id: "Scandic Friends Mastercard" })
|
||||
break
|
||||
case Transactions.rewardType.tui_points:
|
||||
description = intl.formatMessage({ id: "TUI Points" })
|
||||
|
||||
case Transactions.rewardType.pointShop:
|
||||
description = intl.formatMessage({ id: "Scandic Friends Point Shop" })
|
||||
break
|
||||
}
|
||||
|
||||
const arrival = dt(transaction.checkinDate).locale(lang).format("DD MMM YYYY")
|
||||
|
||||
function renderConfirmationNumber() {
|
||||
if (transaction.confirmationNumber === "BALFWD") return null
|
||||
|
||||
if (
|
||||
!isWebview &&
|
||||
transaction.bookingUrl &&
|
||||
(transaction.type === Transactions.rewardType.stay ||
|
||||
transaction.type === Transactions.rewardType.rewardNight)
|
||||
) {
|
||||
return (
|
||||
<Link variant="underscored" href={transaction.bookingUrl}>
|
||||
{transaction.confirmationNumber}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
return transaction.confirmationNumber
|
||||
}
|
||||
|
||||
return (
|
||||
<Table.TR>
|
||||
<Table.TD>
|
||||
<AwardPoints
|
||||
awardPoints={transaction.awardPoints}
|
||||
isCalculated={transaction.pointsCalculated}
|
||||
/>
|
||||
</Table.TD>
|
||||
<Table.TD>
|
||||
<Body textTransform="bold">{description}</Body>
|
||||
</Table.TD>
|
||||
<Table.TD>{renderConfirmationNumber()}</Table.TD>
|
||||
<Table.TD>
|
||||
{transaction.checkinDate && transaction.confirmationNumber !== "BALFWD"
|
||||
? arrival
|
||||
: null}
|
||||
</Table.TD>
|
||||
</Table.TR>
|
||||
)
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
.container {
|
||||
overflow-x: auto;
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
width: 100%;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
border: 1px solid var(--Scandic-Brand-Pale-Peach);
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.container {
|
||||
border-radius: var(--Corner-radius-Large);
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
"use client"
|
||||
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Table from "@/components/TempDesignSystem/Table"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
|
||||
import Row from "./Row"
|
||||
|
||||
import styles from "./clientTable.module.css"
|
||||
|
||||
import type { ClientTableProps } from "@/types/components/myPages/myPage/earnAndBurn"
|
||||
|
||||
const tableHeadings = [
|
||||
"Points",
|
||||
"Description",
|
||||
"Booking number",
|
||||
"Arrival date",
|
||||
]
|
||||
|
||||
export default function ClientTable({ transactions }: ClientTableProps) {
|
||||
const intl = useIntl()
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Table>
|
||||
<Table.THead>
|
||||
<Table.TR>
|
||||
{tableHeadings.map((heading) => (
|
||||
<Table.TH key={heading}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({ id: heading })}
|
||||
</Body>
|
||||
</Table.TH>
|
||||
))}
|
||||
</Table.TR>
|
||||
</Table.THead>
|
||||
<Table.TBody>
|
||||
{transactions.length ? (
|
||||
transactions.map((transaction, index) => (
|
||||
<Row
|
||||
key={`${transaction.confirmationNumber}-${index}`}
|
||||
transaction={transaction}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<Table.TR className={styles.placeholder}>
|
||||
<Table.TD colSpan={tableHeadings.length}>
|
||||
{intl.formatMessage({ id: "No transactions available" })}
|
||||
</Table.TD>
|
||||
</Table.TR>
|
||||
)}
|
||||
</Table.TBody>
|
||||
</Table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { ChevronRightIcon } from "@/components/Icons"
|
||||
|
||||
import styles from "./pagination.module.css"
|
||||
|
||||
import {
|
||||
PaginationButtonProps,
|
||||
PaginationProps,
|
||||
} from "@/types/components/myPages/myPage/earnAndBurn"
|
||||
|
||||
function PaginationButton({
|
||||
children,
|
||||
isActive,
|
||||
handleClick,
|
||||
disabled,
|
||||
}: React.PropsWithChildren<PaginationButtonProps>) {
|
||||
return (
|
||||
<button
|
||||
type={"button"}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
className={`${styles.paginationButton} ${isActive ? styles.paginationButtonActive : ""}`}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Pagination({
|
||||
pageCount,
|
||||
isFetching,
|
||||
handlePageChange,
|
||||
currentPage,
|
||||
}: PaginationProps) {
|
||||
const isOnFirstPage = currentPage === 1
|
||||
const isOnLastPage = currentPage === pageCount
|
||||
return (
|
||||
<div className={styles.pagination}>
|
||||
<PaginationButton
|
||||
disabled={isFetching || isOnFirstPage}
|
||||
handleClick={() => {
|
||||
handlePageChange(currentPage - 1)
|
||||
}}
|
||||
>
|
||||
<ChevronRightIcon className={styles.chevronLeft} />
|
||||
</PaginationButton>
|
||||
{[...Array(pageCount)].map((_, idx) => (
|
||||
<PaginationButton
|
||||
isActive={currentPage === idx + 1}
|
||||
disabled={isFetching || currentPage === idx + 1}
|
||||
key={idx}
|
||||
handleClick={() => {
|
||||
handlePageChange(idx + 1)
|
||||
}}
|
||||
>
|
||||
{idx + 1}
|
||||
</PaginationButton>
|
||||
))}
|
||||
<PaginationButton
|
||||
disabled={isFetching || isOnLastPage}
|
||||
handleClick={() => {
|
||||
handlePageChange(currentPage + 1)
|
||||
}}
|
||||
>
|
||||
<ChevronRightIcon />
|
||||
</PaginationButton>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
padding: var(--Spacing-x2);
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
border-radius: var(--Corner-radius-Rounded);
|
||||
margin: auto;
|
||||
gap: var(--Spacing-x5);
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.paginationButton {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
font-size: var(--typography-Body-Bold-fontSize);
|
||||
font-weight: var(--typography-Body-Bold-fontWeight);
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.paginationButton[disabled] {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.chevronLeft {
|
||||
transform: rotate(180deg);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.paginationButtonActive {
|
||||
color: var(--WHITE);
|
||||
background-color: var(--Base-Text-Accent);
|
||||
border-radius: var(--Corner-radius-Rounded);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import ClientJourney from "./Client"
|
||||
|
||||
export default async function JourneyTable() {
|
||||
const initialJourneyTransactions =
|
||||
await serverClient().user.transaction.friendTransactions({
|
||||
page: 1,
|
||||
limit: 5,
|
||||
})
|
||||
if (!initialJourneyTransactions?.data) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<ClientJourney initialJourneyTransactions={initialJourneyTransactions} />
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import SectionContainer from "@/components/Section/Container"
|
||||
import SectionHeader from "@/components/Section/Header"
|
||||
import SectionLink from "@/components/Section/Link"
|
||||
|
||||
import JourneyTable from "./JourneyTable"
|
||||
|
||||
import type { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage"
|
||||
|
||||
export default function EarnAndBurn({
|
||||
link,
|
||||
subtitle,
|
||||
title,
|
||||
}: AccountPageComponentProps) {
|
||||
return (
|
||||
<SectionContainer>
|
||||
<SectionHeader title={title} link={link} preamble={subtitle} />
|
||||
<JourneyTable />
|
||||
<SectionLink link={link} variant="mobile" />
|
||||
</SectionContainer>
|
||||
)
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-x: auto;
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.container {
|
||||
border-radius: var(--Corner-radius-Large);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
"use client"
|
||||
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
|
||||
import Table from "@/components/TempDesignSystem/Table"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import AwardPoints from "../../EarnAndBurn/AwardPoints"
|
||||
|
||||
const tableHeadings = ["Points", "Expiration Date"]
|
||||
|
||||
export default function ExpiringPointsTable({
|
||||
points,
|
||||
expirationDate,
|
||||
}: {
|
||||
points: number
|
||||
expirationDate: string
|
||||
}) {
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
const expiration = dt(expirationDate).locale(lang).format("DD MMM YYYY")
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<Table.THead>
|
||||
<Table.TR>
|
||||
{tableHeadings.map((heading) => (
|
||||
<Table.TH key={heading}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({ id: heading })}
|
||||
</Body>
|
||||
</Table.TH>
|
||||
))}
|
||||
</Table.TR>
|
||||
</Table.THead>
|
||||
<Table.TBody>
|
||||
<Table.TR>
|
||||
<Table.TD>
|
||||
<AwardPoints awardPoints={points} isCalculated isExpiringPoints />
|
||||
</Table.TD>
|
||||
<Table.TD>{expiration}</Table.TD>
|
||||
</Table.TR>
|
||||
</Table.TBody>
|
||||
</Table>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
.table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.thead {
|
||||
background-color: var(--Main-Grey-10);
|
||||
border-left: 1px solid var(--Main-Grey-10);
|
||||
border-right: 1px solid var(--Main-Grey-10);
|
||||
}
|
||||
|
||||
.tr {
|
||||
border: 1px solid var(--Main-Grey-10);
|
||||
}
|
||||
|
||||
.th {
|
||||
text-align: left;
|
||||
padding: var(--Spacing-x2) var(--Spacing-x4);
|
||||
}
|
||||
|
||||
.td {
|
||||
text-align: left;
|
||||
padding: var(--Spacing-x2) var(--Spacing-x4);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import SectionContainer from "@/components/Section/Container"
|
||||
import SectionHeader from "@/components/Section/Header"
|
||||
|
||||
import ExpiringPointsTable from "./ExpiringPointsTable"
|
||||
|
||||
import { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage"
|
||||
|
||||
export default async function ExpiringPoints({
|
||||
link,
|
||||
subtitle,
|
||||
title,
|
||||
}: AccountPageComponentProps) {
|
||||
const membershipLevel = await serverClient().user.membershipLevel()
|
||||
|
||||
if (!membershipLevel?.pointsToExpire || !membershipLevel?.pointsExpiryDate) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<SectionContainer>
|
||||
<SectionHeader title={title} link={link} preamble={subtitle} />
|
||||
<ExpiringPointsTable
|
||||
points={membershipLevel.pointsToExpire}
|
||||
expirationDate={membershipLevel.pointsExpiryDate}
|
||||
/>
|
||||
</SectionContainer>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { MembershipLevelEnum } from "@/constants/membershipLevels"
|
||||
|
||||
import { getIntl } from "@/i18n"
|
||||
import { getMembershipLevelObject } from "@/utils/membershipLevel"
|
||||
import { getMembership } from "@/utils/user"
|
||||
|
||||
import PointsContainer from "../../../Overview/Stats/Points/Container"
|
||||
import {
|
||||
NextLevelNightsColumn,
|
||||
NextLevelPointsColumn,
|
||||
StayOnLevelColumn,
|
||||
YourPointsColumn,
|
||||
} from "../../../Overview/Stats/Points/PointsColumn"
|
||||
|
||||
import { UserProps } from "@/types/components/myPages/user"
|
||||
import { LangParams } from "@/types/params"
|
||||
|
||||
/* TODO */
|
||||
export default async function Points({ user, lang }: UserProps & LangParams) {
|
||||
const { formatMessage } = await getIntl()
|
||||
|
||||
const membership = getMembership(user.memberships)
|
||||
const nextLevel = getMembershipLevelObject(
|
||||
membership?.nextLevel as MembershipLevelEnum,
|
||||
lang
|
||||
)
|
||||
|
||||
return (
|
||||
<PointsContainer>
|
||||
<YourPointsColumn points={membership?.currentPoints} />
|
||||
{nextLevel && (
|
||||
<>
|
||||
{membership?.currentPoints ? (
|
||||
<StayOnLevelColumn
|
||||
points={membership?.currentPoints} //TODO
|
||||
subtitle={`${formatMessage({ id: "by" })} ${membership?.expirationDate}`}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<NextLevelPointsColumn
|
||||
points={membership?.pointsRequiredToNextlevel}
|
||||
subtitle={`${formatMessage({ id: "next level:" })} ${nextLevel.name}`}
|
||||
/>
|
||||
{membership?.nightsToTopTier && (
|
||||
<NextLevelNightsColumn
|
||||
nights={membership.nightsToTopTier}
|
||||
subtitle={
|
||||
membership.tierExpirationDate &&
|
||||
`by ${membership.tierExpirationDate}`
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</PointsContainer>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { getProfile } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import SectionContainer from "@/components/Section/Container"
|
||||
import SectionHeader from "@/components/Section/Header"
|
||||
import SectionLink from "@/components/Section/Link"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
|
||||
import Friend from "../../Overview/Friend"
|
||||
import Hero from "../../Overview/Friend/Hero"
|
||||
import MembershipNumber from "../../Overview/Friend/MembershipNumber"
|
||||
import Stats from "../../Overview/Stats"
|
||||
|
||||
import styles from "./overview.module.css"
|
||||
|
||||
import type { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage"
|
||||
|
||||
export default async function PointsOverview({
|
||||
link,
|
||||
subtitle,
|
||||
title,
|
||||
}: AccountPageComponentProps) {
|
||||
const user = await getProfile()
|
||||
if (!user || "error" in user) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<SectionContainer>
|
||||
<SectionHeader link={link} preamble={subtitle} title={title} topTitle />
|
||||
<Hero color="burgundy">
|
||||
<Friend membership={user.membership} name={user.name}>
|
||||
<MembershipNumber color="red" membership={user.membership} />
|
||||
</Friend>
|
||||
<Divider className={styles.divider} color="peach" />
|
||||
<Stats user={user} />
|
||||
</Hero>
|
||||
<SectionLink link={link} variant="mobile" />
|
||||
</SectionContainer>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
.divider {
|
||||
padding-top: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.divider {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user