diff --git a/app/[lang]/(live)/(protected)/my-pages/[...path]/page.tsx b/app/[lang]/(live)/(protected)/my-pages/[...path]/page.tsx index 46882e1d7..b61739b18 100644 --- a/app/[lang]/(live)/(protected)/my-pages/[...path]/page.tsx +++ b/app/[lang]/(live)/(protected)/my-pages/[...path]/page.tsx @@ -12,6 +12,11 @@ export default async function MyPages({ }: PageArgs) { const accountPage = await serverClient().contentstack.accountPage.get() const { formatMessage } = await getIntl() + + if (!accountPage) { + return null + } + return (
{accountPage.content.length ? ( diff --git a/app/[lang]/(live)/@header/[...paths]/@languageSwitcher/page.tsx b/app/[lang]/(live)/@header/[...paths]/@languageSwitcher/page.tsx index e96bc295c..960fb22ba 100644 --- a/app/[lang]/(live)/@header/[...paths]/@languageSwitcher/page.tsx +++ b/app/[lang]/(live)/@header/[...paths]/@languageSwitcher/page.tsx @@ -4,6 +4,8 @@ import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher" export default async function LanguageSwitcherRoute() { const data = await serverClient().contentstack.languageSwitcher.get() - + if (!data) { + return null + } return } diff --git a/app/[lang]/(live)/@header/[...paths]/layout.tsx b/app/[lang]/(live)/@header/[...paths]/layout.tsx index 3601c3e2f..8b88b75e1 100644 --- a/app/[lang]/(live)/@header/[...paths]/layout.tsx +++ b/app/[lang]/(live)/@header/[...paths]/layout.tsx @@ -1,5 +1,3 @@ -import { ReactNode } from "react" - import Header from "@/components/Current/Header" import { LangParams, PageArgs } from "@/types/params" @@ -7,15 +5,8 @@ import { LangParams, PageArgs } from "@/types/params" export default function HeaderLayout({ params, languageSwitcher, - children, }: PageArgs & { - languageSwitcher: ReactNode - children: ReactNode + languageSwitcher: React.ReactNode }) { - return ( - <> -
- {children} - - ) + return
} diff --git a/app/[lang]/(live-current)/@languageSwitcher/current-content-page/page.tsx b/app/[lang]/(live-current)/@languageSwitcher/current-content-page/page.tsx index e96bc295c..960fb22ba 100644 --- a/app/[lang]/(live-current)/@languageSwitcher/current-content-page/page.tsx +++ b/app/[lang]/(live-current)/@languageSwitcher/current-content-page/page.tsx @@ -4,6 +4,8 @@ import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher" export default async function LanguageSwitcherRoute() { const data = await serverClient().contentstack.languageSwitcher.get() - + if (!data) { + return null + } return } diff --git a/components/ContentType/LoyaltyPage.tsx b/components/ContentType/LoyaltyPage.tsx index c90b03a33..811fbf7f9 100644 --- a/components/ContentType/LoyaltyPage.tsx +++ b/components/ContentType/LoyaltyPage.tsx @@ -10,6 +10,9 @@ import type { LangParams } from "@/types/params" export default async function LoyaltyPage({ lang }: LangParams) { const loyaltyPage = await serverClient().contentstack.loyaltyPage.get() + if (!loyaltyPage) { + return null + } return (
{loyaltyPage.sidebar.length ? ( diff --git a/components/ContentType/Webviews/AccountPage.tsx b/components/ContentType/Webviews/AccountPage.tsx index d93b28565..0d18c3152 100644 --- a/components/ContentType/Webviews/AccountPage.tsx +++ b/components/ContentType/Webviews/AccountPage.tsx @@ -14,6 +14,9 @@ import { LangParams } from "@/types/params" export default async function MyPages({ lang }: LangParams) { const accountPage = await serverClient().contentstack.accountPage.get() + if (!accountPage) { + return null + } const linkToOverview = `/${lang}/webview${accountPage.url}` !== overview[lang] diff --git a/components/ContentType/Webviews/LoyaltyPage.tsx b/components/ContentType/Webviews/LoyaltyPage.tsx index 1548e8a2d..b0d9f80c5 100644 --- a/components/ContentType/Webviews/LoyaltyPage.tsx +++ b/components/ContentType/Webviews/LoyaltyPage.tsx @@ -11,6 +11,9 @@ import { LangParams } from "@/types/params" export default async function AboutScandicFriends({ lang }: LangParams) { const loyaltyPage = await serverClient().contentstack.loyaltyPage.get() + if (!loyaltyPage) { + return null + } return (
diff --git a/components/Current/Footer/index.tsx b/components/Current/Footer/index.tsx index 5f44f4fa3..ac9d3d982 100644 --- a/components/Current/Footer/index.tsx +++ b/components/Current/Footer/index.tsx @@ -10,6 +10,9 @@ import { LangParams } from "@/types/params" export default async function Footer({ lang }: LangParams) { const footerData = await serverClient().contentstack.base.footer({ lang }) + if (!footerData) { + return null + } return (
diff --git a/components/Current/Header/LanguageSwitcher/Mobile/mobile.module.css b/components/Current/Header/LanguageSwitcher/Mobile/mobile.module.css index 7175026e3..08f31defb 100644 --- a/components/Current/Header/LanguageSwitcher/Mobile/mobile.module.css +++ b/components/Current/Header/LanguageSwitcher/Mobile/mobile.module.css @@ -71,4 +71,4 @@ .mobile { display: none; } -} +} \ No newline at end of file diff --git a/components/Current/Header/index.tsx b/components/Current/Header/index.tsx index ca3c8e855..b72164ab4 100644 --- a/components/Current/Header/index.tsx +++ b/components/Current/Header/index.tsx @@ -21,6 +21,10 @@ export default async function Header({ }) const session = await auth() + if (!data) { + return null + } + const homeHref = homeHrefs[env.NODE_ENV][lang] const { frontpage_link_text, logo, menu, top_menu } = data diff --git a/components/Loyalty/Blocks/DynamicContent/index.tsx b/components/Loyalty/Blocks/DynamicContent/index.tsx index 0a447cb5c..f40719452 100644 --- a/components/Loyalty/Blocks/DynamicContent/index.tsx +++ b/components/Loyalty/Blocks/DynamicContent/index.tsx @@ -19,6 +19,9 @@ async function DynamicComponentBlock({ component }: DynamicComponentProps) { const session = await auth() const user = session ? await serverClient().user.get() : null + if (!user) { + return null + } switch (component) { case LoyaltyComponentEnum.how_it_works: diff --git a/components/Loyalty/Sidebar/JoinLoyalty/Contact/ContactRow/index.tsx b/components/Loyalty/Sidebar/JoinLoyalty/Contact/ContactRow/index.tsx index e0ba98085..fef04c911 100644 --- a/components/Loyalty/Sidebar/JoinLoyalty/Contact/ContactRow/index.tsx +++ b/components/Loyalty/Sidebar/JoinLoyalty/Contact/ContactRow/index.tsx @@ -10,6 +10,9 @@ import type { ContactRowProps } from "@/types/components/loyalty/sidebar" export default async function ContactRow({ contact }: ContactRowProps) { const data = await serverClient().contentstack.base.contact() + if (!data) { + return null + } const val = getValueFromContactConfig(contact.contact_field, data) diff --git a/components/Loyalty/Sidebar/JoinLoyalty/index.tsx b/components/Loyalty/Sidebar/JoinLoyalty/index.tsx index 30c291ee7..43e1804c6 100644 --- a/components/Loyalty/Sidebar/JoinLoyalty/index.tsx +++ b/components/Loyalty/Sidebar/JoinLoyalty/index.tsx @@ -30,15 +30,19 @@ export default async function JoinLoyaltyContact({ {block.preamble ? ( {block.preamble} ) : null} - - - + + {formatMessage({ id: "Already a friend?" })}
{formatMessage({ id: "Click here to log in" })} -
- + +
{block.contact ? : null}
diff --git a/components/Loyalty/Sidebar/JoinLoyalty/joinLoyalty.module.css b/components/Loyalty/Sidebar/JoinLoyalty/joinLoyalty.module.css index 81d2dc8cb..cc464abac 100644 --- a/components/Loyalty/Sidebar/JoinLoyalty/joinLoyalty.module.css +++ b/components/Loyalty/Sidebar/JoinLoyalty/joinLoyalty.module.css @@ -10,12 +10,3 @@ gap: var(--Spacing-x5); padding: var(--Spacing-x4) var(--Spacing-x2) var(--Spacing-x5); } - -/* TODO: Remove when we get proper button variables */ -.link { - font-family: var(--typography-Body-Bold-fontFamily); - font-size: var(--typography-Body-Bold-fontSize); - font-weight: var(--typography-Body-Bold-fontWeight); - letter-spacing: var(--typography-Body-Bold-letterSpacing); - line-height: var(--typography-Body-Bold-lineHeight); -} diff --git a/components/Loyalty/Sidebar/index.tsx b/components/Loyalty/Sidebar/index.tsx index 3e7fe428a..4eaf8d8d9 100644 --- a/components/Loyalty/Sidebar/index.tsx +++ b/components/Loyalty/Sidebar/index.tsx @@ -32,8 +32,8 @@ export default function SidebarLoyalty({ return ( ) default: diff --git a/components/MyPages/Blocks/Benefits/CurrentLevel/current.module.css b/components/MyPages/Blocks/Benefits/CurrentLevel/current.module.css index 15e551baa..a92d55d1d 100644 --- a/components/MyPages/Blocks/Benefits/CurrentLevel/current.module.css +++ b/components/MyPages/Blocks/Benefits/CurrentLevel/current.module.css @@ -18,4 +18,4 @@ justify-content: center; min-height: 280px; padding: var(--Spacing-x7) var(--Spacing-x3); -} +} \ No newline at end of file diff --git a/components/MyPages/Blocks/Challenges/challenges.module.css b/components/MyPages/Blocks/Challenges/challenges.module.css index 3ecfe5ef2..efe78075e 100644 --- a/components/MyPages/Blocks/Challenges/challenges.module.css +++ b/components/MyPages/Blocks/Challenges/challenges.module.css @@ -17,29 +17,6 @@ grid-area: header; } -.subtitle { - color: var(--some-black-color, #000); - font-family: var(--typography-Script-1-fontFamily); - font-size: 1.6rem; - font-weight: 400; - line-height: 1.8rem; - margin: 0; -} - -.title { - color: var(--some-black-color, #000); - font-family: var(--typography-Title-1-fontFamily); - font-size: 1.6rem; - font-weight: 900; - inline-size: 18rem; - line-height: 1.8rem; - margin: 0; - overflow-wrap: break-word; - padding: 0; - text-align: center; - text-transform: uppercase; -} - .section { display: grid; gap: 0.8rem; @@ -121,17 +98,6 @@ grid-template-columns: 1fr; } - .journey .subtitle { - font-size: 2.6rem; - line-height: 3.2rem; - } - - .journey .title { - font-size: 2.6rem; - inline-size: 25rem; - line-height: 3.2rem; - } - .victories { grid-template-columns: 1fr; grid-template-rows: var(--card-height) 1fr 1fr; @@ -139,20 +105,11 @@ .circle { align-items: center; - background-color: var(--some-white-color, #fff); + background-color: var(--Main-Grey-White); border-radius: 50%; display: flex; height: 2rem; justify-content: center; width: 2rem; } - - .victory .subtitle { - font-size: 1.3rem; - line-height: 1.6rem; - } - - .victory .title { - inline-size: 13rem; - } } diff --git a/components/MyPages/Blocks/Challenges/index.tsx b/components/MyPages/Blocks/Challenges/index.tsx index 454727c92..693edda91 100644 --- a/components/MyPages/Blocks/Challenges/index.tsx +++ b/components/MyPages/Blocks/Challenges/index.tsx @@ -1,4 +1,5 @@ import Image from "@/components/Image" +import BiroScript from "@/components/TempDesignSystem/Text/BiroScript" import Title from "@/components/TempDesignSystem/Text/Title" import { getIntl } from "@/i18n" @@ -25,8 +26,10 @@ export default async function Challenges({
{journeys.map((journey) => (
-

{journey.tag}

-

{journey.title}

+ {journey.tag} + + {journey.title} +
))}
@@ -48,8 +51,10 @@ export default async function Challenges({ width={12} /> -

{victory.tag}

-

{victory.title}

+ {victory.tag} + + {victory.title} + ))}
diff --git a/components/MyPages/Blocks/Overview/index.tsx b/components/MyPages/Blocks/Overview/index.tsx index 7c5c7ed98..385edcdf7 100644 --- a/components/MyPages/Blocks/Overview/index.tsx +++ b/components/MyPages/Blocks/Overview/index.tsx @@ -16,6 +16,9 @@ export default async function Overview({ title, }: AccountPageComponentProps) { const user = await serverClient().user.get() + if (!user) { + return null + } return (
diff --git a/components/MyPages/Blocks/Points/CurrentPointsBalance/index.tsx b/components/MyPages/Blocks/Points/CurrentPointsBalance/index.tsx index 8bde4529b..7627b3435 100644 --- a/components/MyPages/Blocks/Points/CurrentPointsBalance/index.tsx +++ b/components/MyPages/Blocks/Points/CurrentPointsBalance/index.tsx @@ -16,16 +16,19 @@ async function CurrentPointsBalance({ }: AccountPageComponentProps) { const user = await serverClient().user.get() const { formatMessage } = await getIntl() + if (!user) { + return null + } const membership = getMembership(user.memberships) return (
-

{`${formatMessage({ id: "Total points" })}*`}

-

{`${formatMessage({ id: "Points" })}: ${membership?.currentPoints || "N/A"}`}

+

{`${formatMessage({ id: "Total Points" })}*`}

+

+ {`${formatMessage({ id: "Points" })}: ${membership?.currentPoints || "N/A"}`} +

{`*${formatMessage({ id: "Points may take up to 10 days to be displayed." })}`}

diff --git a/components/MyPages/Blocks/Points/EarnAndBurn/Client.tsx b/components/MyPages/Blocks/Points/EarnAndBurn/Client.tsx new file mode 100644 index 000000000..494357be6 --- /dev/null +++ b/components/MyPages/Blocks/Points/EarnAndBurn/Client.tsx @@ -0,0 +1,45 @@ +"use client" + +import { trpc } from "@/lib/trpc/client" + +import DesktopTable from "./Desktop" +import MobileTable from "./Mobile" + +import type { + ClientEarnAndBurnProps, + TransactionsObject, +} from "@/types/components/myPages/myPage/earnAndBurn" + +export default function ClientEarnAndBurn({ + initialData, + lang, +}: ClientEarnAndBurnProps) { + /** + * desctruct fetchNextPage, hasNextPage once pagination is + * possible through API + */ + const { data } = trpc.user.transaction.friendTransactions.useInfiniteQuery( + { limit: 5 }, + { + getNextPageParam: (lastPage) => lastPage?.nextCursor, + initialData: { + pageParams: [undefined, 1], + pages: [initialData], + }, + } + ) + + // TS having a hard time with the filtered type. + // This is only temporary as we will not return null + // later on when we handle errors appropriately. + const filteredTransactions = (data?.pages.filter( + (page) => page && page.data + ) ?? []) as unknown as TransactionsObject[] + const transactions = filteredTransactions.flatMap((page) => page.data) + return ( + <> + + + + ) +} diff --git a/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/Row/index.tsx b/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/Row/index.tsx new file mode 100644 index 000000000..1ee31be53 --- /dev/null +++ b/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/Row/index.tsx @@ -0,0 +1,35 @@ +import { useIntl } from "react-intl" + +import { dt } from "@/lib/dt" + +import styles from "./row.module.css" + +import type { RowProps } from "@/types/components/myPages/myPage/earnAndBurn" + +export default function Row({ transaction, lang }: RowProps) { + const { formatMessage } = useIntl() + const description = + transaction.hotelName && transaction.city + ? `${transaction.hotelName}, ${transaction.city} ${transaction.nights} ${formatMessage({ id: "nights" })}` + : `${transaction.nights} ${formatMessage({ id: "nights" })}` + const arrival = dt(transaction.checkinDate).locale(lang).format("DD MMM YYYY") + const departure = dt(transaction.checkoutDate) + .locale(lang) + .format("DD MMM YYYY") + const values = [ + arrival, + description, + transaction.confirmationNumber, + departure, + transaction.awardPoints, + ] + return ( + + {values.map((value, idx) => ( + + {value} + + ))} + + ) +} diff --git a/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/Row/row.module.css b/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/Row/row.module.css new file mode 100644 index 000000000..2fc5bc1f7 --- /dev/null +++ b/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/Row/row.module.css @@ -0,0 +1,8 @@ +.tr { + border: 1px solid #e6e9ec; +} + +.td { + text-align: left; + padding: 16px 32px; +} diff --git a/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/desktop.module.css b/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/desktop.module.css new file mode 100644 index 000000000..987c60642 --- /dev/null +++ b/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/desktop.module.css @@ -0,0 +1,36 @@ +.container { + display: none; +} + +.table { + border-collapse: collapse; + border-spacing: 0; + 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); +} + +.th { + text-align: left; + padding: 20px 32px; +} + +.placeholder { + width: 100%; + padding: 24px; + text-align: center; + border: 1px solid var(--Main-Grey-10); +} + +@media screen and (min-width: 768px) { + .container { + display: flex; + flex-direction: column; + gap: 16px; + overflow-x: auto; + } +} diff --git a/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/index.tsx b/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/index.tsx new file mode 100644 index 000000000..1fb622fbd --- /dev/null +++ b/components/MyPages/Blocks/Points/EarnAndBurn/Desktop/index.tsx @@ -0,0 +1,74 @@ +import { useIntl } from "react-intl" + +import Row from "./Row" + +import styles from "./desktop.module.css" + +import type { TableProps } from "@/types/components/myPages/myPage/earnAndBurn" + +const tableHeadings = [ + "Arrival date", + "Description", + "Booking number", + "Transaction date", + "Points", +] + +export default function DesktopTable({ lang, transactions }: TableProps) { + const { formatMessage } = useIntl() + return ( +
+ {transactions.length ? ( + + + + {tableHeadings.map((heading) => ( + + ))} + + + + {transactions.map((transaction) => ( + + ))} + +
+ {formatMessage({ id: heading })} +
+ ) : ( + // TODO: add once pagination is available through API + // + + + + {tableHeadings.map((heading) => ( + + ))} + + + + + + + +
+ {heading} +
+ {formatMessage({ id: "No transactions available" })} +
+ )} +
+ ) +} diff --git a/components/MyPages/Blocks/Points/EarnAndBurn/Mobile/index.tsx b/components/MyPages/Blocks/Points/EarnAndBurn/Mobile/index.tsx new file mode 100644 index 000000000..725f502c2 --- /dev/null +++ b/components/MyPages/Blocks/Points/EarnAndBurn/Mobile/index.tsx @@ -0,0 +1,63 @@ +import { useIntl } from "react-intl" + +import { dt } from "@/lib/dt" + +import Body from "@/components/TempDesignSystem/Text/Body" + +import styles from "./mobile.module.css" + +import type { TableProps } from "@/types/components/myPages/myPage/earnAndBurn" + +export default function MobileTable({ lang, transactions }: TableProps) { + const { formatMessage } = useIntl() + return ( +
+ + + + + + + + + + + + + {transactions.length ? ( + transactions.map((transaction) => ( + + + + + )) + ) : ( + + + + )} + +
+ {formatMessage({ id: "Transactions" })} + {formatMessage({ id: "Points" })}
+ + {dt(transaction.checkinDate) + .locale(lang) + .format("DD MMM YYYY")} + + {transaction.hotelName && transaction.city ? ( + {`${transaction.hotelName}, ${transaction.city}`} + ) : null} + + {`${transaction.nights} ${formatMessage({ id: transaction.nights === 1 ? "night" : "nights" })}`} + + + {`${transaction.awardPoints} P`} +
+ {formatMessage({ id: "Empty" })} +
+
+ ) +} diff --git a/components/MyPages/Blocks/Points/EarnAndBurn/Mobile/mobile.module.css b/components/MyPages/Blocks/Points/EarnAndBurn/Mobile/mobile.module.css new file mode 100644 index 000000000..d3ca085e7 --- /dev/null +++ b/components/MyPages/Blocks/Points/EarnAndBurn/Mobile/mobile.module.css @@ -0,0 +1,46 @@ +.table { + border-collapse: collapse; + border-spacing: 0; + width: 100%; +} + +.thead { + background-color: var(--Main-Grey-10); +} + +.th { + padding: var(--Spacing-x2); +} + +.tr { + border-top: 1px solid var(--Main-Grey-10); +} + +.td { + padding: var(--Spacing-x2); +} + +.transactionDetails { + display: grid; + font-size: var(--typography-Footnote-Regular-fontSize); +} + +.transactionDate { + font-weight: 700; +} + +.transactionPoints { + font-size: var(--typography-Body-Regular-fontSize); +} + +.placeholder { + text-align: center; + padding: var(--Spacing-x4); + border: 1px solid var(--Main-Grey-10); +} + +@media screen and (min-width: 768px) { + .container { + display: none; + } +} diff --git a/components/MyPages/Blocks/Points/EarnAndBurn/earnAndBurn.module.css b/components/MyPages/Blocks/Points/EarnAndBurn/earnAndBurn.module.css index f0f64cb4c..230868385 100644 --- a/components/MyPages/Blocks/Points/EarnAndBurn/earnAndBurn.module.css +++ b/components/MyPages/Blocks/Points/EarnAndBurn/earnAndBurn.module.css @@ -2,97 +2,3 @@ display: grid; gap: var(--Spacing-x3); } - -.mobileTable { - border-collapse: collapse; - border-spacing: 0; - width: 100%; -} - -.mobileThead { - background-color: var(--Main-Grey-10); -} - -.mobileTh { - font-size: var(--typography-Body-Regular-fontSize); - font-weight: 500; - padding: var(--Spacing-x2); - text-align: left; -} - -.mobileTr { - border-top: 1px solid var(--Main-Grey-10); -} - -.mobileTd { - padding: var(--Spacing-x2); -} - -.mobileTransactionDetails { - display: grid; - font-size: var(--typography-Footnote-Regular-fontSize); -} - -.mobileTransactionDate { - font-weight: 700; -} - -.mobileTransactionPoints { - font-size: var(--typography-Body-Regular-fontSize); -} - -.mobilePlaceholder { - text-align: center; - padding: var(--Spacing-x4); - border: 1px solid var(--Main-Grey-10); -} - -.tableContainer { - display: none; -} - -.table { - border-collapse: collapse; - border-spacing: 0; - 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 #e6e9ec; -} - -.th { - text-align: left; - padding: 20px 32px; -} - -.td { - text-align: left; - padding: 16px 32px; -} - -.placeholder { - width: 100%; - padding: 24px; - text-align: center; - border: 1px solid var(--Main-Grey-10); -} - -@media screen and (min-width: 768px) { - .mobileTableContainer { - display: none; - } - - .tableContainer { - display: flex; - flex-direction: column; - gap: 16px; - overflow-x: auto; - } -} diff --git a/components/MyPages/Blocks/Points/EarnAndBurn/index.tsx b/components/MyPages/Blocks/Points/EarnAndBurn/index.tsx index 51e5b6533..57d117843 100644 --- a/components/MyPages/Blocks/Points/EarnAndBurn/index.tsx +++ b/components/MyPages/Blocks/Points/EarnAndBurn/index.tsx @@ -1,187 +1,28 @@ -"use client" -import { useIntl } from "react-intl" - -import { dt } from "@/lib/dt" -import { trpc } from "@/lib/trpc/client" +import { serverClient } from "@/lib/trpc/server" import Header from "@/components/SectionHeader" +import ClientEarnAndBurn from "./Client" + import styles from "./earnAndBurn.module.css" -import { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage" -import { Page, RowProps } from "@/types/components/myPages/myPage/earnAndBurn" +import type { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage" -const tableHeadings = [ - "Arrival date", - "Description", - "Booking number", - "Transaction date", - "Points", -] - -function EarnAndBurn({ +export default async function EarnAndBurn({ lang, - title, - subtitle, link, + subtitle, + title, }: AccountPageComponentProps) { - const intl = useIntl() - const { data, hasNextPage, fetchNextPage } = - trpc.user.transaction.friendTransactions.useInfiniteQuery( - { limit: 5 }, - { - getNextPageParam: (lastPage: Page) => lastPage.nextCursor, - } - ) - - function loadMoreData() { - if (hasNextPage) { - fetchNextPage() - } + const initialTransactions = + await serverClient().user.transaction.friendTransactions({ limit: 5 }) + if (!initialTransactions) { + return null } - - const transactions = data?.pages.flatMap((page) => page.data) ?? [] return (
- -
- - - - - - - - - {transactions.length ? ( - transactions.map((transaction) => ( - - - - - )) - ) : ( - - - - )} - -
- {intl.formatMessage({ id: "Transactions" })} - - {intl.formatMessage({ id: "Points" })} -
- - {dt(transaction.checkinDate) - .locale(lang) - .format("DD MMM YYYY")} - - {transaction.hotelName && transaction.city ? ( - {`${transaction.hotelName}, ${transaction.city}`} - ) : null} - - {`${transaction.nights} ${intl.formatMessage({ id: transaction.nights === 1 ? "night" : "nights" })}`} - - - {`${transaction.awardPoints} P`} -
- {intl.formatMessage({ id: "Empty" })} -
-
-
- {transactions.length ? ( - - - - {tableHeadings.map((heading) => ( - - ))} - - - - {transactions.map((transaction) => ( - - ))} - -
- {intl.formatMessage({ id: heading })} -
- ) : ( - // TODO: add once pagination is available through API - // - - - - {tableHeadings.map((heading) => ( - - ))} - - - - - - - -
- {heading} -
- {intl.formatMessage({ id: "No transactions available" })} -
- )} -
+
) } - -function Row({ transaction, lang }: RowProps) { - const intl = useIntl() - const description = - transaction.hotelName && transaction.city - ? `${intl.formatMessage({ id: transaction.hotelName })}, ${transaction.city} ${transaction.nights} ${intl.formatMessage({ id: "nights" })}` - : `${transaction.nights} ${intl.formatMessage({ id: "nights" })}` - const arrival = dt(transaction.checkinDate).locale(lang).format("DD MMM YYYY") - const departure = dt(transaction.checkoutDate) - .locale(lang) - .format("DD MMM YYYY") - const values = [ - arrival, - description, - transaction.confirmationNumber, - departure, - transaction.awardPoints, - ] - return ( - - {values.map((value, idx) => ( - - {value} - - ))} - - ) -} - -export default EarnAndBurn diff --git a/components/MyPages/Blocks/Stays/Previous/Client.tsx b/components/MyPages/Blocks/Stays/Previous/Client.tsx new file mode 100644 index 000000000..11f919fcd --- /dev/null +++ b/components/MyPages/Blocks/Stays/Previous/Client.tsx @@ -0,0 +1,67 @@ +"use client" + +import { trpc } from "@/lib/trpc/client" + +import LoadingSpinner from "@/components/LoadingSpinner" +import Grids from "@/components/TempDesignSystem/Grids" + +import ListContainer from "../ListContainer" +import ShowMoreButton from "../ShowMoreButton" +import StayCard from "../StayCard" +import EmptyPreviousStaysBlock from "./EmptyPreviousStays" + +import type { + PreviousStaysClientProps, + PreviousStaysNonNullResponseObject, +} from "@/types/components/myPages/stays/previous" + +export default function ClientPreviousStays({ + initialPreviousStays, + lang, +}: PreviousStaysClientProps) { + const { data, isFetching, fetchNextPage, hasNextPage, isLoading } = + trpc.user.stays.previous.useInfiniteQuery( + {}, + { + getNextPageParam: (lastPage) => lastPage?.nextCursor, + initialData: { + pageParams: [undefined, 1], + pages: [initialPreviousStays], + }, + } + ) + + function loadMoreData() { + if (hasNextPage) { + fetchNextPage() + } + } + + // TS having a hard time with the filtered type. + // This is only temporary as we will not return null + // later on when we handle errors appropriately. + const filteredStays = (data?.pages.filter((page) => page && page.data) ?? + []) as unknown as PreviousStaysNonNullResponseObject[] + const stays = filteredStays.flatMap((page) => page.data) + + return isLoading ? ( + + ) : stays.length ? ( + + + {stays.map((stay) => ( + + ))} + + {hasNextPage ? ( + + ) : null} + + ) : ( + + ) +} diff --git a/components/MyPages/Blocks/Stays/Previous/index.tsx b/components/MyPages/Blocks/Stays/Previous/index.tsx index c330e98fe..818b68613 100644 --- a/components/MyPages/Blocks/Stays/Previous/index.tsx +++ b/components/MyPages/Blocks/Stays/Previous/index.tsx @@ -1,64 +1,29 @@ -"use client" +import { serverClient } from "@/lib/trpc/server" -import { trpc } from "@/lib/trpc/client" - -import LoadingSpinner from "@/components/LoadingSpinner" -import Header from "@/components/SectionHeader" -import Grids from "@/components/TempDesignSystem/Grids" +import SectionHeader from "@/components/SectionHeader" import Container from "../Container" -import ListContainer from "../ListContainer" -import ShowMoreButton from "../ShowMoreButton" -import StayCard from "../StayCard" -import EmptyPreviousStaysBlock from "./EmptyPreviousStays" +import ClientPreviousStays from "./Client" import type { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage" -export default function PreviousStays({ +export default async function PreviousStays({ lang, title, subtitle, link, }: AccountPageComponentProps) { - const { data, isFetching, fetchNextPage, hasNextPage, isLoading } = - trpc.user.stays.previous.useInfiniteQuery( - {}, - { - getNextPageParam: (lastPage) => lastPage.nextCursor, - } - ) - - function loadMoreData() { - if (hasNextPage) { - fetchNextPage() - } + const initialPreviousStays = await serverClient().user.stays.previous() + if (!initialPreviousStays?.data) { + return null } - - const stays = data?.pages.flatMap((page) => page.data) ?? [] - return ( -
- {isLoading ? ( - - ) : stays.length ? ( - - - {stays.map((stay) => ( - - ))} - - {hasNextPage ? ( - - ) : null} - - ) : ( - - )} + + ) } diff --git a/components/MyPages/Blocks/Stays/Soonest/index.tsx b/components/MyPages/Blocks/Stays/Soonest/index.tsx index 66d724d6c..146404964 100644 --- a/components/MyPages/Blocks/Stays/Soonest/index.tsx +++ b/components/MyPages/Blocks/Stays/Soonest/index.tsx @@ -16,14 +16,17 @@ export default async function SoonestStays({ subtitle, link, }: AccountPageComponentProps) { - const { data: stays } = await serverClient().user.stays.upcoming({ limit: 3 }) + const response = await serverClient().user.stays.upcoming({ limit: 3 }) + if (!response?.data) { + return null + } return (
- {stays.length ? ( + {response.data.length ? ( - {stays.map((stay) => ( + {response.data.map((stay) => (
- - + + + + {" - "} - + + +
diff --git a/components/MyPages/Blocks/Stays/StayCard/stay.module.css b/components/MyPages/Blocks/Stays/StayCard/stay.module.css index e19593c67..1f2604f3a 100644 --- a/components/MyPages/Blocks/Stays/StayCard/stay.module.css +++ b/components/MyPages/Blocks/Stays/StayCard/stay.module.css @@ -36,8 +36,4 @@ align-items: center; display: flex; gap: var(--Spacing-x-half); - font-family: var(--typography-Caption-Regular-fontFamily); - font-size: var(--typography-Caption-Regular-fontSize); - font-weight: var(--typography-Caption-Regular-fontWeight); - line-height: var(--typography-Caption-Regular-lineHeight); } diff --git a/components/MyPages/Blocks/Stays/Upcoming/Client.tsx b/components/MyPages/Blocks/Stays/Upcoming/Client.tsx new file mode 100644 index 000000000..536495cfb --- /dev/null +++ b/components/MyPages/Blocks/Stays/Upcoming/Client.tsx @@ -0,0 +1,67 @@ +"use client" + +import { trpc } from "@/lib/trpc/client" + +import LoadingSpinner from "@/components/LoadingSpinner" +import Grids from "@/components/TempDesignSystem/Grids" + +import ListContainer from "../ListContainer" +import ShowMoreButton from "../ShowMoreButton" +import StayCard from "../StayCard" +import EmptyUpcomingStaysBlock from "./EmptyUpcomingStays" + +import type { + UpcomingStaysClientProps, + UpcomingStaysNonNullResponseObject, +} from "@/types/components/myPages/stays/upcoming" + +export default function ClientUpcomingStays({ + initialUpcomingStays, + lang, +}: UpcomingStaysClientProps) { + const { data, isFetching, fetchNextPage, hasNextPage, isLoading } = + trpc.user.stays.upcoming.useInfiniteQuery( + {}, + { + getNextPageParam: (lastPage) => lastPage?.nextCursor, + initialData: { + pageParams: [undefined, 1], + pages: [initialUpcomingStays], + }, + } + ) + + function loadMoreData() { + if (hasNextPage) { + fetchNextPage() + } + } + + // TS having a hard time with the filtered type. + // This is only temporary as we will not return null + // later on when we handle errors appropriately. + const filteredStays = (data?.pages.filter((page) => page && page.data) ?? + []) as unknown as UpcomingStaysNonNullResponseObject[] + const stays = filteredStays.flatMap((page) => page.data) + + return isLoading ? ( + + ) : stays.length ? ( + + + {stays.map((stay) => ( + + ))} + + {hasNextPage ? ( + + ) : null} + + ) : ( + + ) +} diff --git a/components/MyPages/Blocks/Stays/Upcoming/index.tsx b/components/MyPages/Blocks/Stays/Upcoming/index.tsx index 0d2dfe711..4cc065c14 100644 --- a/components/MyPages/Blocks/Stays/Upcoming/index.tsx +++ b/components/MyPages/Blocks/Stays/Upcoming/index.tsx @@ -1,64 +1,29 @@ -"use client" +import { serverClient } from "@/lib/trpc/server" -import { trpc } from "@/lib/trpc/client" - -import LoadingSpinner from "@/components/LoadingSpinner" -import Header from "@/components/SectionHeader" -import Grids from "@/components/TempDesignSystem/Grids" +import SectionHeader from "@/components/SectionHeader" import Container from "../Container" -import ListContainer from "../ListContainer" -import ShowMoreButton from "../ShowMoreButton" -import StayCard from "../StayCard" -import EmptyUpcomingStaysBlock from "./EmptyUpcomingStays" +import ClientUpcomingStays from "./Client" import type { AccountPageComponentProps } from "@/types/components/myPages/myPage/accountPage" -export default function UpcomingStays({ +export default async function UpcomingStays({ lang, title, subtitle, link, }: AccountPageComponentProps) { - const { data, hasNextPage, isFetching, fetchNextPage, isLoading } = - trpc.user.stays.upcoming.useInfiniteQuery( - { limit: 6 }, - { - getNextPageParam: (lastPage) => lastPage.nextCursor, - } - ) - - function loadMoreData() { - if (hasNextPage) { - fetchNextPage() - } + const initialUpcomingStays = await serverClient().user.stays.upcoming() + if (!initialUpcomingStays?.data) { + return null } - - const stays = data?.pages.flatMap((page) => page.data) ?? [] - return ( -
- {isLoading ? ( - - ) : stays.length ? ( - - - {stays.map((stay) => ( - - ))} - - {hasNextPage ? ( - - ) : null} - - ) : ( - - )} + + ) } diff --git a/components/MyPages/Breadcrumbs/index.tsx b/components/MyPages/Breadcrumbs/index.tsx index 9875026dc..36cacbf17 100644 --- a/components/MyPages/Breadcrumbs/index.tsx +++ b/components/MyPages/Breadcrumbs/index.tsx @@ -1,6 +1,6 @@ import { serverClient } from "@/lib/trpc/server" -import { ChevronRightIcon , HouseIcon } from "@/components/Icons" +import { ChevronRightIcon, HouseIcon } from "@/components/Icons" import Link from "@/components/TempDesignSystem/Link" import Footnote from "@/components/TempDesignSystem/Text/Footnote" @@ -8,6 +8,9 @@ import styles from "./breadcrumbs.module.css" export default async function Breadcrumbs() { const breadcrumbs = await serverClient().contentstack.breadcrumbs.get() + if (!breadcrumbs) { + return null + } const homeBreadcrumb = breadcrumbs.shift() return (