mirror of
https://github.com/lukevella/rallly.git
synced 2025-04-30 10:46:35 +02:00
✨ Add pagination to events page (#1689)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
parent
9adebe496b
commit
8d2e5f8359
2 changed files with 82 additions and 41 deletions
|
@ -16,6 +16,7 @@ import {
|
||||||
EmptyStateIcon,
|
EmptyStateIcon,
|
||||||
EmptyStateTitle,
|
EmptyStateTitle,
|
||||||
} from "@/components/empty-state";
|
} from "@/components/empty-state";
|
||||||
|
import { Pagination } from "@/components/pagination";
|
||||||
import { StackedList, StackedListItem } from "@/components/stacked-list";
|
import { StackedList, StackedListItem } from "@/components/stacked-list";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { getScheduledEvents } from "@/features/scheduled-event/api/get-scheduled-events";
|
import { getScheduledEvents } from "@/features/scheduled-event/api/get-scheduled-events";
|
||||||
|
@ -30,17 +31,22 @@ import { EventsTabbedView } from "./events-tabbed-view";
|
||||||
async function loadData({
|
async function loadData({
|
||||||
status,
|
status,
|
||||||
search,
|
search,
|
||||||
|
page = 1,
|
||||||
|
pageSize = 10,
|
||||||
}: {
|
}: {
|
||||||
status: Status;
|
status: Status;
|
||||||
search?: string;
|
search?: string;
|
||||||
|
page?: number;
|
||||||
|
pageSize?: number;
|
||||||
}) {
|
}) {
|
||||||
const { userId } = await requireUser();
|
const { userId } = await requireUser();
|
||||||
const scheduledEvents = await getScheduledEvents({
|
return getScheduledEvents({
|
||||||
userId,
|
userId,
|
||||||
status,
|
status,
|
||||||
search,
|
search,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
});
|
});
|
||||||
return scheduledEvents;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ScheduledEventEmptyState({ status }: { status: Status }) {
|
async function ScheduledEventEmptyState({ status }: { status: Status }) {
|
||||||
|
@ -98,11 +104,24 @@ export default async function Page({
|
||||||
searchParams,
|
searchParams,
|
||||||
}: {
|
}: {
|
||||||
params: Params;
|
params: Params;
|
||||||
searchParams?: { status: string; q?: string };
|
searchParams?: { status: string; q?: string; page?: string };
|
||||||
}) {
|
}) {
|
||||||
const { t } = await getTranslation(params.locale);
|
const { t } = await getTranslation(params.locale);
|
||||||
const status = statusSchema.catch("upcoming").parse(searchParams?.status);
|
const status = statusSchema.catch("upcoming").parse(searchParams?.status);
|
||||||
const scheduledEvents = await loadData({ status, search: searchParams?.q });
|
const pageParam = searchParams?.page;
|
||||||
|
const page = pageParam ? Math.max(1, Number(pageParam) || 1) : 1;
|
||||||
|
const pageSize = 10;
|
||||||
|
|
||||||
|
const {
|
||||||
|
events: paginatedEvents,
|
||||||
|
totalCount,
|
||||||
|
totalPages,
|
||||||
|
} = await loadData({
|
||||||
|
status,
|
||||||
|
search: searchParams?.q,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
|
@ -127,12 +146,12 @@ export default async function Page({
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{scheduledEvents.length === 0 && (
|
{paginatedEvents.length === 0 && (
|
||||||
<ScheduledEventEmptyState status={status} />
|
<ScheduledEventEmptyState status={status} />
|
||||||
)}
|
)}
|
||||||
{scheduledEvents.length > 0 && (
|
{paginatedEvents.length > 0 && (
|
||||||
<StackedList>
|
<StackedList>
|
||||||
{scheduledEvents.map((event) => (
|
{paginatedEvents.map((event) => (
|
||||||
<StackedListItem key={event.id}>
|
<StackedListItem key={event.id}>
|
||||||
<ScheduledEventListItem
|
<ScheduledEventListItem
|
||||||
eventId={event.id}
|
eventId={event.id}
|
||||||
|
@ -149,6 +168,14 @@ export default async function Page({
|
||||||
))}
|
))}
|
||||||
</StackedList>
|
</StackedList>
|
||||||
)}
|
)}
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<Pagination
|
||||||
|
currentPage={page}
|
||||||
|
totalPages={totalPages}
|
||||||
|
totalItems={totalCount}
|
||||||
|
pageSize={pageSize}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</EventsTabbedView>
|
</EventsTabbedView>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { Prisma } from "@rallly/database";
|
||||||
import { prisma } from "@rallly/database";
|
import { prisma } from "@rallly/database";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import timezone from "dayjs/plugin/timezone";
|
import timezone from "dayjs/plugin/timezone";
|
||||||
|
@ -19,22 +20,29 @@ export async function getScheduledEvents({
|
||||||
userId,
|
userId,
|
||||||
status,
|
status,
|
||||||
search,
|
search,
|
||||||
|
page = 1,
|
||||||
|
pageSize = 10,
|
||||||
}: {
|
}: {
|
||||||
userId: string;
|
userId: string;
|
||||||
status: Status;
|
status: Status;
|
||||||
search?: string;
|
search?: string;
|
||||||
|
page?: number;
|
||||||
|
pageSize?: number;
|
||||||
}) {
|
}) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
const rawEvents = await prisma.scheduledEvent.findMany({
|
const where: Prisma.ScheduledEventWhereInput = {
|
||||||
where: {
|
|
||||||
userId,
|
userId,
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
...(status != "past" && { start: { gte: now } }),
|
...(status != "past" && { start: { gte: now } }),
|
||||||
...(status === "past" && { start: { lt: now } }),
|
...(status === "past" && { start: { lt: now } }),
|
||||||
...(search && { title: { contains: search, mode: "insensitive" } }),
|
...(search && { title: { contains: search, mode: "insensitive" } }),
|
||||||
status: mapStatus[status],
|
status: mapStatus[status],
|
||||||
},
|
};
|
||||||
|
|
||||||
|
const [rawEvents, totalCount] = await Promise.all([
|
||||||
|
prisma.scheduledEvent.findMany({
|
||||||
|
where,
|
||||||
orderBy: {
|
orderBy: {
|
||||||
start: status === "past" ? "desc" : "asc",
|
start: status === "past" ? "desc" : "asc",
|
||||||
},
|
},
|
||||||
|
@ -60,14 +68,17 @@ export async function getScheduledEvents({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
skip: (page - 1) * pageSize,
|
||||||
|
take: pageSize,
|
||||||
|
}),
|
||||||
|
prisma.scheduledEvent.count({ where }),
|
||||||
|
]);
|
||||||
|
|
||||||
const events = rawEvents.map((event) => ({
|
const events = rawEvents.map((event) => ({
|
||||||
...event,
|
...event,
|
||||||
status:
|
status:
|
||||||
event.status === "confirmed"
|
event.status === "confirmed"
|
||||||
? // If the event is confirmed, it's either past or upcoming
|
? ((event.start < now ? "past" : "upcoming") as Status)
|
||||||
((event.start < now ? "past" : "upcoming") as Status)
|
|
||||||
: event.status,
|
: event.status,
|
||||||
invites: event.invites.map((invite) => ({
|
invites: event.invites.map((invite) => ({
|
||||||
id: invite.id,
|
id: invite.id,
|
||||||
|
@ -76,5 +87,8 @@ export async function getScheduledEvents({
|
||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return events;
|
const totalPages = Math.ceil(totalCount / pageSize);
|
||||||
|
const hasNextPage = page * pageSize < totalCount;
|
||||||
|
|
||||||
|
return { events, totalCount, totalPages, hasNextPage };
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue