refactor(orders): add useOrdersInfiniteQuery for improved pagination and add load more button in orders list components

This commit is contained in:
vchikalkin 2025-07-22 12:28:10 +03:00
parent 8b0f93bf23
commit 60002a7169
3 changed files with 75 additions and 18 deletions

View File

@ -2,8 +2,9 @@
import { OrderCard } from '@/components/shared/order-card';
import { useCustomerQuery, useIsMaster } from '@/hooks/api/customers';
import { useOrdersQuery } from '@/hooks/api/orders';
import { useOrdersInfiniteQuery } from '@/hooks/api/orders';
import { useDateTimeStore } from '@/stores/datetime';
import { Button } from '@repo/ui/components/ui/button';
import { getDateUTCRange } from '@repo/utils/datetime-format';
export function ClientsOrdersList() {
@ -14,7 +15,12 @@ export function ClientsOrdersList() {
const selectedDate = useDateTimeStore((store) => store.date);
const { endOfDay, startOfDay } = getDateUTCRange(selectedDate).day();
const { data: { orders } = {}, isLoading } = useOrdersQuery(
const {
data: { pages } = {},
fetchNextPage,
hasNextPage,
isLoading,
} = useOrdersInfiniteQuery(
{
filters: {
slot: {
@ -31,19 +37,23 @@ export function ClientsOrdersList() {
},
},
},
pagination: {
limit: selectedDate ? undefined : 10,
},
},
Boolean(customer?.documentId) && isMaster,
{ enabled: Boolean(customer?.documentId) && isMaster },
);
const orders = pages?.flatMap((page) => page.orders) ?? [];
if (!orders?.length || isLoading || !isMaster) return null;
return (
<div className="flex flex-col space-y-2">
<h1 className="font-bold">Записи клиентов</h1>
{orders?.map((order) => order && <OrderCard key={order.documentId} showDate {...order} />)}
{hasNextPage && (
<Button onClick={() => fetchNextPage()} variant="ghost">
Загрузить еще
</Button>
)}
</div>
);
}
@ -54,7 +64,12 @@ export function OrdersList() {
const selectedDate = useDateTimeStore((store) => store.date);
const { endOfDay, startOfDay } = getDateUTCRange(selectedDate).day();
const { data: { orders } = {}, isLoading } = useOrdersQuery(
const {
data: { pages } = {},
fetchNextPage,
hasNextPage,
isLoading,
} = useOrdersInfiniteQuery(
{
filters: {
client: {
@ -71,13 +86,12 @@ export function OrdersList() {
: undefined,
},
},
pagination: {
limit: selectedDate ? undefined : 10,
},
},
Boolean(customer?.documentId),
{ enabled: Boolean(customer?.documentId) },
);
const orders = pages?.flatMap((page) => page.orders) ?? [];
if (!orders?.length || isLoading) return null;
return (
@ -87,6 +101,11 @@ export function OrdersList() {
(order) =>
order && <OrderCard avatarSource="master" key={order.documentId} showDate {...order} />,
)}
{hasNextPage && (
<Button onClick={() => fetchNextPage()} variant="ghost">
Загрузить еще
</Button>
)}
</div>
);
}

View File

@ -3,7 +3,8 @@
import { OrderCard } from '../shared/order-card';
import { type ProfileProps } from './types';
import { useCustomerQuery, useIsMaster } from '@/hooks/api/customers';
import { useOrdersQuery } from '@/hooks/api/orders';
import { useOrdersInfiniteQuery } from '@/hooks/api/orders';
import { Button } from '@repo/ui/components/ui/button';
export function ProfileOrdersList({ telegramId }: Readonly<ProfileProps>) {
const { data: { customer } = {} } = useCustomerQuery();
@ -11,7 +12,12 @@ export function ProfileOrdersList({ telegramId }: Readonly<ProfileProps>) {
const { data: { customer: profile } = {} } = useCustomerQuery({ telegramId });
const { data: { orders } = {}, isLoading } = useOrdersQuery(
const {
data: { pages } = {},
fetchNextPage,
hasNextPage,
isLoading,
} = useOrdersInfiniteQuery(
{
filters: {
client: {
@ -27,13 +33,12 @@ export function ProfileOrdersList({ telegramId }: Readonly<ProfileProps>) {
},
},
},
pagination: {
limit: 5,
},
},
Boolean(profile?.documentId) && Boolean(customer?.documentId),
{ enabled: Boolean(profile?.documentId) && Boolean(customer?.documentId) },
);
const orders = pages?.flatMap((page) => page.orders) ?? [];
if (!orders?.length || isLoading) return null;
return (
@ -50,6 +55,11 @@ export function ProfileOrdersList({ telegramId }: Readonly<ProfileProps>) {
/>
),
)}
{hasNextPage && (
<Button onClick={() => fetchNextPage()} variant="ghost">
Загрузить еще
</Button>
)}
</div>
);
}

View File

@ -1,7 +1,8 @@
/* eslint-disable unicorn/prevent-abbreviations */
'use client';
import { createOrder, getOrder, getOrders, updateOrder } from '@/actions/api/orders';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
export const useOrderQuery = ({ documentId }: Parameters<typeof getOrder>[0]) =>
useQuery({
@ -37,6 +38,33 @@ export const useOrdersQuery = (variables: Parameters<typeof getOrders>[0], enabl
staleTime: 60 * 1_000,
});
export const useOrdersInfiniteQuery = (
variables: Omit<Parameters<typeof getOrders>[0], 'pagination'>,
{ enabled = true, pageSize = 5 },
) => {
const queryFn = ({ pageParam: page = 1 }) =>
getOrders({
...variables,
pagination: {
page,
pageSize,
},
});
return useInfiniteQuery({
enabled,
getNextPageParam: (lastPage, _allPages, lastPageParameter) => {
if (!lastPage?.orders?.length) return undefined;
return lastPageParameter + 1;
},
initialPageParam: 1,
queryFn,
queryKey: ['orders', variables, 'infinite'],
staleTime: 60 * 1_000,
});
};
export const useOrderMutation = ({
documentId,
}: Pick<Parameters<typeof updateOrder>[0], 'documentId'>) => {