chore: add load more functionality, with refactored css
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -38,3 +38,6 @@ next-env.d.ts
|
|||||||
certificates
|
certificates
|
||||||
# Local Netlify folder
|
# Local Netlify folder
|
||||||
.netlify
|
.netlify
|
||||||
|
|
||||||
|
#vscode
|
||||||
|
.vscode/
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import { _ } from "@/lib/translation"
|
||||||
import { serverClient } from "@/lib/trpc/server"
|
import { serverClient } from "@/lib/trpc/server"
|
||||||
|
|
||||||
import Title from "@/components/MyPages/Title"
|
import Title from "@/components/MyPages/Title"
|
||||||
import Link from "@/components/TempDesignSystem/Link"
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
|
|
||||||
import EmptyUpcomingStaysBlock from "../../Stays/EmptyUpcomingStays"
|
|
||||||
import StayCard from "../../Stays/StayCard"
|
import StayCard from "../../Stays/StayCard"
|
||||||
|
import EmptyUpcomingStaysBlock from "../../Stays/Upcoming/EmptyUpcomingStays"
|
||||||
|
|
||||||
import styles from "./upcoming.module.css"
|
import styles from "./upcoming.module.css"
|
||||||
|
|
||||||
@@ -19,15 +20,15 @@ export default async function UpcomingStays({ lang }: LangParams) {
|
|||||||
<section className={styles.container}>
|
<section className={styles.container}>
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
<Title level="h2" as="h5" uppercase>
|
<Title level="h2" as="h5" uppercase>
|
||||||
Your upcoming stays
|
{_("Your upcoming stays")}
|
||||||
</Title>
|
</Title>
|
||||||
<Link className={styles.link} href="#">
|
<Link className={styles.link} href="#">
|
||||||
See all
|
{_("See all")}
|
||||||
</Link>
|
</Link>
|
||||||
</header>
|
</header>
|
||||||
{stays.length ? (
|
{stays.data.length ? (
|
||||||
<section className={styles.stays}>
|
<section className={styles.stays}>
|
||||||
{stays.map((stay) => (
|
{stays.data.map((stay) => (
|
||||||
<StayCard key={stay.uid} stay={stay} lang={lang} />
|
<StayCard key={stay.uid} stay={stay} lang={lang} />
|
||||||
))}
|
))}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
.container {
|
||||||
|
max-width: var(--max-width);
|
||||||
|
display: grid;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 950px) {
|
||||||
|
.container {
|
||||||
|
gap: 7rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
components/MyPages/Blocks/Stays/Container/index.tsx
Normal file
5
components/MyPages/Blocks/Stays/Container/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import styles from "./container.module.css"
|
||||||
|
|
||||||
|
export default function Container({ children }: React.PropsWithChildren) {
|
||||||
|
return <section className={styles.container}>{children}</section>
|
||||||
|
}
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
.subtitle {
|
.subtitle {
|
||||||
padding-top: 0.5rem;
|
|
||||||
padding-bottom: 2.5rem;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 950px) {
|
@media screen and (min-width: 950px) {
|
||||||
.subtitle {
|
.subtitle {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
padding-top: 2.5rem;
|
}
|
||||||
padding-bottom: 5rem;
|
|
||||||
|
.header {
|
||||||
|
gap: 2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ import Title from "@/components/MyPages/Title"
|
|||||||
|
|
||||||
import styles from "./header.module.css"
|
import styles from "./header.module.css"
|
||||||
|
|
||||||
import { HeaderProps } from "@/types/components/myPages/stays/title"
|
import type { HeaderProps } from "@/types/components/myPages/myStays/title"
|
||||||
|
|
||||||
export default function Header({ title, subtitle }: HeaderProps) {
|
export default function Header({ title, subtitle }: HeaderProps) {
|
||||||
return (
|
return (
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
<Title as="h3" weight="semiBold" uppercase>
|
<Title as="h3" level="h2" weight="semiBold" uppercase>
|
||||||
{title}
|
{title}
|
||||||
</Title>
|
</Title>
|
||||||
<Title as="h5" weight="regular" className={styles.subtitle}>
|
<Title as="h5" level="h3" weight="regular" className={styles.subtitle}>
|
||||||
{subtitle}
|
{subtitle}
|
||||||
</Title>
|
</Title>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
5
components/MyPages/Blocks/Stays/ListContainer/index.tsx
Normal file
5
components/MyPages/Blocks/Stays/ListContainer/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import styles from "./container.module.css"
|
||||||
|
|
||||||
|
export default function ListContainer({ children }: React.PropsWithChildren) {
|
||||||
|
return <section className={styles.container}>{children}</section>
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { _ } from "@/lib/translation"
|
||||||
|
|
||||||
import Title from "@/components/MyPages/Title"
|
import Title from "@/components/MyPages/Title"
|
||||||
|
|
||||||
import styles from "./emptyPreviousStays.module.css"
|
import styles from "./emptyPreviousStays.module.css"
|
||||||
@@ -6,7 +8,7 @@ export default function EmptyPreviousStaysBlock() {
|
|||||||
return (
|
return (
|
||||||
<section className={styles.container}>
|
<section className={styles.container}>
|
||||||
<Title level="h3" as="h5" uppercase>
|
<Title level="h3" as="h5" uppercase>
|
||||||
You have no previous stays.
|
{_("You have no previous stays.")}{" "}
|
||||||
</Title>
|
</Title>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
@@ -1,28 +1,52 @@
|
|||||||
import { serverClient } from "@/lib/trpc/server"
|
"use client"
|
||||||
|
|
||||||
import EmptyPreviousStaysBlock from "../EmptyPreviousStays"
|
import { _ } from "@/lib/translation"
|
||||||
|
import { trpc } from "@/lib/trpc/client"
|
||||||
|
|
||||||
|
import Container from "../Container"
|
||||||
import Header from "../Header"
|
import Header from "../Header"
|
||||||
|
import ListContainer from "../ListContainer"
|
||||||
|
import ShowMoreButton from "../ShowMoreButton"
|
||||||
import StayList from "../StayList"
|
import StayList from "../StayList"
|
||||||
|
import EmptyPreviousStaysBlock from "./EmptyPreviousStays"
|
||||||
|
|
||||||
import styles from "./previous.module.css"
|
import type { Page } from "@/types/components/myPages/myStays/page"
|
||||||
|
|
||||||
import type { LangParams } from "@/types/params"
|
import type { LangParams } from "@/types/params"
|
||||||
|
|
||||||
export default async function PreviousStays({ lang }: LangParams) {
|
export default function PreviousStays({ lang }: LangParams) {
|
||||||
const stays = await serverClient().user.stays.previous()
|
const { data, isFetching, fetchNextPage, hasNextPage } =
|
||||||
|
trpc.user.stays.previous.useInfiniteQuery(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
getNextPageParam: (lastPage: Page) => lastPage.nextCursor,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function loadMoreData() {
|
||||||
|
fetchNextPage()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={styles.container}>
|
<Container>
|
||||||
<Header
|
<Header
|
||||||
title="Your previous stays."
|
title={_("Previous stays")}
|
||||||
subtitle="Revisit your stays and rekindle those our moments together, with ease."
|
subtitle={_(
|
||||||
|
"Revisit your stays and rekindle those our moments together, with ease."
|
||||||
|
)}
|
||||||
></Header>
|
></Header>
|
||||||
|
{data?.pages.length ? (
|
||||||
{stays.length ? (
|
<ListContainer>
|
||||||
<StayList lang={lang} stays={stays} />
|
<StayList
|
||||||
|
lang={lang}
|
||||||
|
stays={data?.pages.flatMap((page) => page.data) ?? []}
|
||||||
|
/>
|
||||||
|
{hasNextPage ? (
|
||||||
|
<ShowMoreButton disabled={isFetching} loadMoreData={loadMoreData} />
|
||||||
|
) : null}
|
||||||
|
</ListContainer>
|
||||||
) : (
|
) : (
|
||||||
<EmptyPreviousStaysBlock />
|
<EmptyPreviousStaysBlock />
|
||||||
)}
|
)}
|
||||||
</section>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
.container {
|
|
||||||
max-width: var(--max-width);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
24
components/MyPages/Blocks/Stays/ShowMoreButton/index.tsx
Normal file
24
components/MyPages/Blocks/Stays/ShowMoreButton/index.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
|
|
||||||
|
import styles from "./button.module.css"
|
||||||
|
|
||||||
|
import type { ShowMoreButtonParams } from "@/types/components/myPages/myStays/button"
|
||||||
|
|
||||||
|
export default function ShowMoreButton({
|
||||||
|
disabled,
|
||||||
|
loadMoreData,
|
||||||
|
}: ShowMoreButtonParams) {
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<Button
|
||||||
|
disabled={disabled}
|
||||||
|
intent="primary"
|
||||||
|
bgcolor="white"
|
||||||
|
type="button"
|
||||||
|
onClick={loadMoreData}
|
||||||
|
>
|
||||||
|
Show more
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,12 +5,12 @@ import Title from "@/components/MyPages/Title"
|
|||||||
|
|
||||||
import styles from "./stay.module.css"
|
import styles from "./stay.module.css"
|
||||||
|
|
||||||
import type { StayCardProps } from "@/types/components/myPages/stays/stayCard"
|
import type { StayCardProps } from "@/types/components/myPages/myStays/stayCard"
|
||||||
|
|
||||||
export default function StayCard({
|
export default function StayCard({
|
||||||
stay,
|
stay,
|
||||||
lang,
|
lang,
|
||||||
showDayCount = false,
|
shouldShowDayCount = false,
|
||||||
}: StayCardProps) {
|
}: StayCardProps) {
|
||||||
const { dateArrive, dateDepart, guests, hotel } = stay
|
const { dateArrive, dateDepart, guests, hotel } = stay
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ export default function StayCard({
|
|||||||
return (
|
return (
|
||||||
<article className={styles.stay}>
|
<article className={styles.stay}>
|
||||||
<div className={styles.imageContainer}>
|
<div className={styles.imageContainer}>
|
||||||
{showDayCount ? (
|
{shouldShowDayCount ? (
|
||||||
<div className={styles.badge}>
|
<div className={styles.badge}>
|
||||||
<time className={styles.time}>In {daysUntilArrival} days</time>
|
<time className={styles.time}>In {daysUntilArrival} days</time>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,29 +1,15 @@
|
|||||||
import Button from "@/components/TempDesignSystem/Button"
|
|
||||||
|
|
||||||
import StayCard from "../StayCard"
|
import StayCard from "../StayCard"
|
||||||
|
|
||||||
import styles from "./stayList.module.css"
|
import styles from "./stayList.module.css"
|
||||||
|
|
||||||
import { StayListProps } from "@/types/components/myPages/stays/stayList"
|
import { StayListProps } from "@/types/components/myPages/myStays/stayList"
|
||||||
|
|
||||||
export default function StayList({ lang, stays }: StayListProps) {
|
export default function StayList({ lang, stays }: StayListProps) {
|
||||||
return (
|
return (
|
||||||
<section>
|
<section className={styles.stays}>
|
||||||
<section className={styles.stays}>
|
{stays.map((stay) => (
|
||||||
{stays.map((stay) => (
|
<StayCard key={stay.uid} stay={stay} lang={lang} />
|
||||||
<StayCard
|
))}
|
||||||
key={stay.uid}
|
|
||||||
stay={stay}
|
|
||||||
lang={lang}
|
|
||||||
showDayCount={true}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</section>
|
|
||||||
<div className={styles.buttonContainer}>
|
|
||||||
<Button intent="primary" type="button">
|
|
||||||
Show more
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,18 +15,8 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttonContainer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 950px) {
|
@media screen and (min-width: 950px) {
|
||||||
.stays {
|
.stays {
|
||||||
grid-template-columns: repeat(auto-fit, minmax(25rem, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(25rem, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttonContainer {
|
|
||||||
margin-top: 4rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.redTitle {
|
.grayTitle {
|
||||||
color: var(--some-red-color, #ed2027);
|
color: var(--some-grey-color, #727272);
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
|
||||||
|
import { _ } from "@/lib/translation"
|
||||||
|
|
||||||
import Title from "@/components/MyPages/Title"
|
import Title from "@/components/MyPages/Title"
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
|
|
||||||
@@ -9,17 +11,15 @@ export default function EmptyUpcomingStaysBlock() {
|
|||||||
return (
|
return (
|
||||||
<section className={styles.container}>
|
<section className={styles.container}>
|
||||||
<Title level="h3" as="h5" uppercase>
|
<Title level="h3" as="h5" uppercase>
|
||||||
You have no upcoming stays.
|
{_(" You have no upcoming stays.")}
|
||||||
<span className={styles.redTitle}> Where should you go next?</span>
|
<span className={styles.grayTitle}>
|
||||||
|
{" "}
|
||||||
|
{_("Where should you go next?")}
|
||||||
|
</span>
|
||||||
</Title>
|
</Title>
|
||||||
<Button
|
<Button intent={"primary"} bgcolor={"quarternary"} asChild type="button">
|
||||||
intent={"primary"}
|
|
||||||
className={styles.button}
|
|
||||||
asChild
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<Link className={styles.link} href={"#"} key={"getInspired"}>
|
<Link className={styles.link} href={"#"} key={"getInspired"}>
|
||||||
Get inspired
|
{_("Get inspired")}
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</section>
|
</section>
|
||||||
@@ -1,29 +1,52 @@
|
|||||||
import { serverClient } from "@/lib/trpc/server"
|
"use client"
|
||||||
|
|
||||||
import EmptyUpcomingStaysBlock from "../EmptyUpcomingStays"
|
import { _ } from "@/lib/translation"
|
||||||
|
import { trpc } from "@/lib/trpc/client"
|
||||||
|
|
||||||
|
import Container from "../Container"
|
||||||
import Header from "../Header"
|
import Header from "../Header"
|
||||||
|
import ListContainer from "../ListContainer"
|
||||||
|
import ShowMoreButton from "../ShowMoreButton"
|
||||||
import StayList from "../StayList"
|
import StayList from "../StayList"
|
||||||
|
import EmptyUpcomingStaysBlock from "./EmptyUpcomingStays"
|
||||||
|
|
||||||
import styles from "./upcoming.module.css"
|
import type { Page } from "@/types/components/myPages/myStays/page"
|
||||||
|
|
||||||
import type { LangParams } from "@/types/params"
|
import type { LangParams } from "@/types/params"
|
||||||
|
|
||||||
export default async function UpcomingStays({ lang }: LangParams) {
|
export default function UpcomingStays({ lang }: LangParams) {
|
||||||
const stays = await serverClient().user.stays.upcoming()
|
const { data, hasNextPage, isFetching, fetchNextPage } =
|
||||||
|
trpc.user.stays.upcoming.useInfiniteQuery(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
getNextPageParam: (lastPage: Page) => lastPage.nextCursor,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function loadMoreData() {
|
||||||
|
fetchNextPage()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={styles.container}>
|
<Container>
|
||||||
<Header
|
<Header
|
||||||
title="Your upcoming stays."
|
title={_("Upcoming stays")}
|
||||||
subtitle="Excited about your next trip? So are we. Below are your upcoming stays
|
subtitle={_(
|
||||||
with us, complete with all the details you need to make each visit
|
"Excited about your next trip? So are we. Below are your upcoming stays with us, complete with all the details you need to make each visit perfect. Can't wait to welcome you back, friend!"
|
||||||
perfect. Can't wait to welcome you back, friend!"
|
)}
|
||||||
></Header>
|
></Header>
|
||||||
{stays.length ? (
|
{data?.pages.length ? (
|
||||||
<StayList lang={lang} stays={stays} />
|
<ListContainer>
|
||||||
|
<StayList
|
||||||
|
lang={lang}
|
||||||
|
stays={data?.pages.flatMap((page) => page.data) ?? []}
|
||||||
|
/>
|
||||||
|
{hasNextPage ? (
|
||||||
|
<ShowMoreButton disabled={isFetching} loadMoreData={loadMoreData} />
|
||||||
|
) : null}
|
||||||
|
</ListContainer>
|
||||||
) : (
|
) : (
|
||||||
<EmptyUpcomingStaysBlock />
|
<EmptyUpcomingStaysBlock />
|
||||||
)}
|
)}
|
||||||
</section>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
.container {
|
|
||||||
max-width: var(--max-width);
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,6 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
import * as api from "@/lib/api"
|
import * as api from "@/lib/api"
|
||||||
import {
|
|
||||||
benefits,
|
|
||||||
extendedUser,
|
|
||||||
nextLevelPerks,
|
|
||||||
previousStays,
|
|
||||||
upcomingStays,
|
|
||||||
} from "./temp"
|
|
||||||
import {
|
import {
|
||||||
badRequestError,
|
badRequestError,
|
||||||
forbiddenError,
|
forbiddenError,
|
||||||
@@ -13,9 +8,15 @@ import {
|
|||||||
unauthorizedError,
|
unauthorizedError,
|
||||||
} from "@/server/errors/trpc"
|
} from "@/server/errors/trpc"
|
||||||
import { protectedProcedure, router } from "@/server/trpc"
|
import { protectedProcedure, router } from "@/server/trpc"
|
||||||
import { z } from "zod"
|
|
||||||
|
|
||||||
import { getUserSchema } from "./output"
|
import { getUserSchema } from "./output"
|
||||||
|
import {
|
||||||
|
benefits,
|
||||||
|
extendedUser,
|
||||||
|
nextLevelPerks,
|
||||||
|
previousStays,
|
||||||
|
upcomingStays,
|
||||||
|
} from "./temp"
|
||||||
|
|
||||||
function fakingRequest<T>(payload: T): Promise<T> {
|
function fakingRequest<T>(payload: T): Promise<T> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@@ -34,7 +35,6 @@ export const userQueryRouter = router({
|
|||||||
Authorization: `Bearer ${ctx.session.token.access_token}`,
|
Authorization: `Bearer ${ctx.session.token.access_token}`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!apiResponse.ok) {
|
if (!apiResponse.ok) {
|
||||||
switch (apiResponse.status) {
|
switch (apiResponse.status) {
|
||||||
case 400:
|
case 400:
|
||||||
@@ -67,7 +67,7 @@ export const userQueryRouter = router({
|
|||||||
name: `${verifiedData.data.name} ${verifiedData.data.lastName}`,
|
name: `${verifiedData.data.name} ${verifiedData.data.lastName}`,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.info(`GEt User Error`)
|
console.info(`Get User Error`)
|
||||||
console.error(error)
|
console.error(error)
|
||||||
throw internalServerError()
|
throw internalServerError()
|
||||||
}
|
}
|
||||||
@@ -90,25 +90,74 @@ export const userQueryRouter = router({
|
|||||||
.object({
|
.object({
|
||||||
perPage: z.number().min(0).default(6),
|
perPage: z.number().min(0).default(6),
|
||||||
page: z.number().min(0).default(0),
|
page: z.number().min(0).default(0),
|
||||||
|
cursor: z.number().nullish(),
|
||||||
})
|
})
|
||||||
.default({})
|
.default({})
|
||||||
)
|
)
|
||||||
.query(async (opts) => {
|
.query(async (opts) => {
|
||||||
const { perPage, page } = opts.input
|
const { perPage, page, cursor } = opts.input
|
||||||
return previousStays.slice(page * perPage, page * perPage + perPage)
|
let nextCursor: typeof cursor | undefined = undefined
|
||||||
|
const nrPages = Math.ceil(previousStays.length / perPage)
|
||||||
|
|
||||||
|
let stays, nextPage
|
||||||
|
if (cursor) {
|
||||||
|
stays = previousStays.slice(cursor, perPage + cursor + 1)
|
||||||
|
nextPage = cursor / perPage + 1
|
||||||
|
} else {
|
||||||
|
stays = previousStays.slice(
|
||||||
|
page * perPage,
|
||||||
|
page * perPage + perPage + 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(nextPage && nextPage < nrPages && stays.length == perPage + 1) ||
|
||||||
|
(!nextPage && nrPages > 1)
|
||||||
|
) {
|
||||||
|
const nextItem = stays.pop()
|
||||||
|
if (nextItem) {
|
||||||
|
nextCursor = previousStays.indexOf(nextItem)
|
||||||
|
}
|
||||||
|
} // TODO: Make request to get user data from Scandic API
|
||||||
|
return { data: stays, nextCursor }
|
||||||
}),
|
}),
|
||||||
|
|
||||||
upcoming: protectedProcedure
|
upcoming: protectedProcedure
|
||||||
.input(
|
.input(
|
||||||
z
|
z
|
||||||
.object({
|
.object({
|
||||||
perPage: z.number().min(0).default(6),
|
perPage: z.number().min(0).default(6),
|
||||||
page: z.number().min(0).default(0),
|
page: z.number().min(0).default(0),
|
||||||
|
cursor: z.number().nullish(),
|
||||||
})
|
})
|
||||||
.default({})
|
.default({})
|
||||||
)
|
)
|
||||||
.query(async (opts) => {
|
.query(async (opts) => {
|
||||||
const { perPage, page } = opts.input
|
const { perPage, page, cursor } = opts.input
|
||||||
return upcomingStays.slice(page * perPage, page * perPage + perPage)
|
let nextCursor: typeof cursor | undefined = undefined
|
||||||
|
const nrPages = Math.ceil(upcomingStays.length / perPage)
|
||||||
|
|
||||||
|
let stays, nextPage
|
||||||
|
if (cursor) {
|
||||||
|
stays = upcomingStays.slice(cursor, perPage + cursor + 1)
|
||||||
|
nextPage = cursor / perPage + 1
|
||||||
|
} else {
|
||||||
|
stays = upcomingStays.slice(
|
||||||
|
page * perPage,
|
||||||
|
page * perPage + perPage + 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(nextPage && nextPage < nrPages && stays.length == perPage + 1) ||
|
||||||
|
(!nextPage && nrPages > 1)
|
||||||
|
) {
|
||||||
|
const nextItem = stays.pop()
|
||||||
|
if (nextItem) {
|
||||||
|
nextCursor = upcomingStays.indexOf(nextItem)
|
||||||
|
}
|
||||||
|
} // TODO: Make request to get user data from Scandic API
|
||||||
|
return { data: stays, nextCursor }
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { randomUUID } from "crypto"
|
||||||
|
|
||||||
import { dt } from "@/lib/dt"
|
import { dt } from "@/lib/dt"
|
||||||
|
|
||||||
export const benefits = [
|
export const benefits = [
|
||||||
@@ -115,168 +117,182 @@ export const shortcuts = [
|
|||||||
|
|
||||||
export const previousStays = [
|
export const previousStays = [
|
||||||
{
|
{
|
||||||
uid: "0",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("04 27 2024"),
|
dateArrive: new Date("04 27 2024"),
|
||||||
dateDepart: new Date("04 28 2024"),
|
dateDepart: new Date("04 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Helsinki Hub",
|
hotel: "Scandic Helsinki Hub",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "1",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("05 27 2024"),
|
dateArrive: new Date("05 27 2024"),
|
||||||
dateDepart: new Date("05 28 2024"),
|
dateDepart: new Date("05 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Örebro Central",
|
hotel: "Scandic Örebro Central",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "2",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("06 27 2024"),
|
dateArrive: new Date("06 27 2024"),
|
||||||
dateDepart: new Date("06 28 2024"),
|
dateDepart: new Date("06 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Oslo City",
|
hotel: "Scandic Oslo City",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "3",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("04 27 2024"),
|
dateArrive: new Date("04 27 2024"),
|
||||||
dateDepart: new Date("04 28 2024"),
|
dateDepart: new Date("04 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Lorem",
|
hotel: "Scandic Lorem",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "4",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("05 27 2024"),
|
dateArrive: new Date("05 27 2024"),
|
||||||
dateDepart: new Date("05 28 2024"),
|
dateDepart: new Date("05 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Ipsum",
|
hotel: "Scandic Ipsum",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "5",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("06 27 2024"),
|
dateArrive: new Date("06 27 2024"),
|
||||||
dateDepart: new Date("06 28 2024"),
|
dateDepart: new Date("06 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Dolor Sin Amet",
|
hotel: "Scandic Dolor Sin Amet",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "6",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("06 27 2024"),
|
dateArrive: new Date("06 27 2024"),
|
||||||
dateDepart: new Date("06 28 2024"),
|
dateDepart: new Date("06 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Anglais",
|
hotel: "Scandic Anglais",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "7",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("06 27 2024"),
|
dateArrive: new Date("06 27 2024"),
|
||||||
dateDepart: new Date("06 28 2024"),
|
dateDepart: new Date("06 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Park",
|
hotel: "Scandic Park",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "8",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("06 27 2024"),
|
dateArrive: new Date("06 27 2024"),
|
||||||
dateDepart: new Date("06 28 2024"),
|
dateDepart: new Date("06 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Klara",
|
hotel: "Scandic Klara",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "9",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("06 27 2024"),
|
dateArrive: new Date("06 27 2024"),
|
||||||
dateDepart: new Date("06 28 2024"),
|
dateDepart: new Date("06 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Dolor A",
|
hotel: "Scandic Järva Krog",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "10",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("06 27 2024"),
|
dateArrive: new Date("06 27 2024"),
|
||||||
dateDepart: new Date("06 28 2024"),
|
dateDepart: new Date("06 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic B",
|
hotel: "Scandic Kiruna",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "11",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("06 27 2024"),
|
dateArrive: new Date("06 27 2024"),
|
||||||
dateDepart: new Date("06 28 2024"),
|
dateDepart: new Date("06 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic C",
|
hotel: "Scandic Umeå",
|
||||||
},
|
|
||||||
{
|
|
||||||
uid: "12",
|
|
||||||
dateArrive: new Date("06 27 2024"),
|
|
||||||
dateDepart: new Date("06 28 2024"),
|
|
||||||
guests: 2,
|
|
||||||
hotel: "Scandic D",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
uid: "13",
|
|
||||||
dateArrive: new Date("06 27 2024"),
|
|
||||||
dateDepart: new Date("06 28 2024"),
|
|
||||||
guests: 2,
|
|
||||||
hotel: "Scandic E",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
uid: "14",
|
|
||||||
dateArrive: new Date("06 27 2024"),
|
|
||||||
dateDepart: new Date("06 28 2024"),
|
|
||||||
guests: 2,
|
|
||||||
hotel: "Scandic F",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
uid: "15",
|
|
||||||
dateArrive: new Date("06 27 2024"),
|
|
||||||
dateDepart: new Date("06 28 2024"),
|
|
||||||
guests: 2,
|
|
||||||
hotel: "Scandic G",
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const upcomingStays = [
|
export const upcomingStays = [
|
||||||
{
|
{
|
||||||
uid: "0",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("04 27 2024"),
|
dateArrive: new Date("04 27 2024"),
|
||||||
dateDepart: new Date("04 28 2024"),
|
dateDepart: new Date("04 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Helsinki Hub",
|
hotel: "Scandic Helsinki Hub",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "1",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("05 27 2024"),
|
dateArrive: new Date("05 27 2024"),
|
||||||
dateDepart: new Date("05 28 2024"),
|
dateDepart: new Date("05 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Örebro Central",
|
hotel: "Scandic Örebro Central",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "2",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("06 27 2024"),
|
dateArrive: new Date("06 27 2024"),
|
||||||
dateDepart: new Date("06 28 2024"),
|
dateDepart: new Date("06 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Oslo City",
|
hotel: "Scandic Oslo City",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "3",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("04 27 2024"),
|
dateArrive: new Date("04 27 2024"),
|
||||||
dateDepart: new Date("04 28 2024"),
|
dateDepart: new Date("04 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Lorem",
|
hotel: "Scandic Lorem",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "4",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("05 27 2024"),
|
dateArrive: new Date("05 27 2024"),
|
||||||
dateDepart: new Date("05 28 2024"),
|
dateDepart: new Date("05 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Ipsum",
|
hotel: "Scandic Ipsum",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uid: "5",
|
uid: randomUUID(),
|
||||||
dateArrive: new Date("06 27 2024"),
|
dateArrive: new Date("06 27 2024"),
|
||||||
dateDepart: new Date("06 28 2024"),
|
dateDepart: new Date("06 28 2024"),
|
||||||
guests: 2,
|
guests: 2,
|
||||||
hotel: "Scandic Dolor Sin Amet",
|
hotel: "Scandic Dolor Sin Amet",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
uid: randomUUID(),
|
||||||
|
dateArrive: new Date("06 27 2024"),
|
||||||
|
dateDepart: new Date("06 28 2024"),
|
||||||
|
guests: 2,
|
||||||
|
hotel: "Scandic Anglais",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uid: randomUUID(),
|
||||||
|
dateArrive: new Date("06 27 2024"),
|
||||||
|
dateDepart: new Date("06 28 2024"),
|
||||||
|
guests: 2,
|
||||||
|
hotel: "Scandic Park",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uid: randomUUID(),
|
||||||
|
dateArrive: new Date("06 27 2024"),
|
||||||
|
dateDepart: new Date("06 28 2024"),
|
||||||
|
guests: 2,
|
||||||
|
hotel: "Scandic Klara",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uid: randomUUID(),
|
||||||
|
dateArrive: new Date("06 27 2024"),
|
||||||
|
dateDepart: new Date("06 28 2024"),
|
||||||
|
guests: 2,
|
||||||
|
hotel: "Scandic Järva Krog",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uid: randomUUID(),
|
||||||
|
dateArrive: new Date("06 27 2024"),
|
||||||
|
dateDepart: new Date("06 28 2024"),
|
||||||
|
guests: 2,
|
||||||
|
hotel: "Scandic Kiruna",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uid: randomUUID(),
|
||||||
|
dateArrive: new Date("06 27 2024"),
|
||||||
|
dateDepart: new Date("06 28 2024"),
|
||||||
|
guests: 2,
|
||||||
|
hotel: "Scandic Umeå",
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const extendedUser = {
|
export const extendedUser = {
|
||||||
|
dob: dt("1977-07-05").format("YYYY-MM-DD"),
|
||||||
journeys: challenges.journeys,
|
journeys: challenges.journeys,
|
||||||
nights: 14,
|
nights: 14,
|
||||||
shortcuts,
|
shortcuts,
|
||||||
upcomingStays,
|
|
||||||
victories: challenges.victories,
|
victories: challenges.victories,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import { UUID } from "crypto"
|
||||||
|
|
||||||
export type Stay = {
|
export type Stay = {
|
||||||
uid: string
|
uid: UUID
|
||||||
dateArrive: Date
|
dateArrive: Date
|
||||||
dateDepart: Date
|
dateDepart: Date
|
||||||
guests: number
|
guests: number
|
||||||
|
|||||||
4
types/components/myPages/myStays/button.ts
Normal file
4
types/components/myPages/myStays/button.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export type ShowMoreButtonParams = {
|
||||||
|
loadMoreData: () => void
|
||||||
|
disabled: boolean
|
||||||
|
}
|
||||||
6
types/components/myPages/myStays/page.ts
Normal file
6
types/components/myPages/myStays/page.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import type { Stay } from "../myPage/stay"
|
||||||
|
|
||||||
|
export type Page = {
|
||||||
|
data: Stay[]
|
||||||
|
nextCursor?: number
|
||||||
|
}
|
||||||
8
types/components/myPages/myStays/stayCard.ts
Normal file
8
types/components/myPages/myStays/stayCard.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { Lang } from "@/constants/languages"
|
||||||
|
import type { Stay } from "../myPage/stay"
|
||||||
|
|
||||||
|
export type StayCardProps = {
|
||||||
|
lang: Lang
|
||||||
|
shouldShowDayCount?: boolean
|
||||||
|
stay: Stay
|
||||||
|
}
|
||||||
7
types/components/myPages/myStays/stayList.ts
Normal file
7
types/components/myPages/myStays/stayList.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { Lang } from "@/constants/languages"
|
||||||
|
import type { Stay } from "../myPage/stay"
|
||||||
|
|
||||||
|
export type StayListProps = {
|
||||||
|
stays: Stay[]
|
||||||
|
lang: Lang
|
||||||
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { Stay } from "../myPage/stay"
|
|
||||||
import { Lang } from "@/constants/languages"
|
|
||||||
|
|
||||||
export type StayCardProps = {
|
|
||||||
lang: Lang
|
|
||||||
showDayCount?: boolean
|
|
||||||
stay: Stay
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import { Lang } from "@/constants/languages"
|
|
||||||
import { Stay } from "../myPage/stay"
|
|
||||||
|
|
||||||
export type StayListProps = {
|
|
||||||
stays: Stay[]
|
|
||||||
lang: Lang
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user