import autoAnimate from "@formkit/auto-animate"; import { GetStaticPaths, GetStaticProps } from "next"; import { useRouter } from "next/router"; import { Fragment, useEffect, useRef } from "react"; import { z } from "zod"; import { WipeMyCalActionButton } from "@calcom/app-store/wipemycalother/components"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { inferQueryInput, inferQueryOutput, trpc } from "@calcom/trpc/react"; import { Alert } from "@calcom/ui/Alert"; import { Icon } from "@calcom/ui/Icon"; import { Button, EmptyScreen } from "@calcom/ui/v2"; import BookingLayout from "@calcom/ui/v2/core/layouts/BookingLayout"; import { useInViewObserver } from "@lib/hooks/useInViewObserver"; import BookingListItem from "@components/booking/BookingListItem"; import SkeletonLoader from "@components/v2/bookings/SkeletonLoader"; type BookingListingStatus = inferQueryInput<"viewer.bookings">["status"]; type BookingOutput = inferQueryOutput<"viewer.bookings">["bookings"][0]; const validStatuses = ["upcoming", "recurring", "past", "cancelled", "unconfirmed"] as const; const descriptionByStatus: Record = { upcoming: "upcoming_bookings", recurring: "recurring_bookings", past: "past_bookings", cancelled: "cancelled_bookings", unconfirmed: "unconfirmed_bookings", }; const querySchema = z.object({ status: z.enum(validStatuses), }); export default function Bookings() { const router = useRouter(); const { status } = router.isReady ? querySchema.parse(router.query) : { status: "upcoming" as const }; const { t } = useLocale(); const query = trpc.useInfiniteQuery(["viewer.bookings", { status, limit: 10 }], { // first render has status `undefined` enabled: router.isReady, getNextPageParam: (lastPage) => lastPage.nextCursor, }); // Animate page (tab) tranistions to look smoothing const animationParentRef = useRef(null); const buttonInView = useInViewObserver(() => { if (!query.isFetching && query.hasNextPage && query.status === "success") { query.fetchNextPage(); } }); const isEmpty = !query.data?.pages[0]?.bookings.length; // Get all recurring events of the series with the same recurringEventId const defineRecurrentBookings = ( booking: BookingOutput, groupedBookings: Record ) => { let recurringBookings = undefined; if (booking.recurringEventId !== null) { recurringBookings = groupedBookings[booking.recurringEventId]; } return { recurringBookings }; }; const shownBookings: Record = {}; const filterBookings = (booking: BookingOutput) => { if (status === "recurring" || status === "cancelled") { if (!booking.recurringEventId) { return true; } if ( shownBookings[booking.recurringEventId] !== undefined && shownBookings[booking.recurringEventId].length > 0 ) { shownBookings[booking.recurringEventId].push(booking); return false; } shownBookings[booking.recurringEventId] = [booking]; } return true; }; useEffect(() => { animationParentRef.current && autoAnimate(animationParentRef.current); }, [animationParentRef]); return (
{query.status === "error" && ( )} {(query.status === "loading" || query.status === "idle") && } {query.status === "success" && !isEmpty && (
{/* TODO: add today only for the current day

{t("today")}

*/}
{query.data.pages.map((page, index) => ( {page.bookings.filter(filterBookings).map((booking: BookingOutput) => ( ))} ))}
)} {query.status === "success" && isEmpty && (
)}
); } export const getStaticProps: GetStaticProps = (ctx) => { const params = querySchema.safeParse(ctx.params); if (!params.success) return { notFound: true }; return { props: { status: params.data.status, }, }; }; export const getStaticPaths: GetStaticPaths = () => { return { paths: validStatuses.map((status) => ({ params: { status }, locale: "en", })), fallback: "blocking", }; };