mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 17:43:47 +00:00
fix: add pagination to campaigns list
The campaigns page was fetching only the first 50 items with no way to load more. Switched from useQuery to useInfiniteQuery with a "Load more" button so all campaigns are accessible.
This commit is contained in:
@@ -2031,6 +2031,7 @@
|
|||||||
"subtitle": "Manage advertising links",
|
"subtitle": "Manage advertising links",
|
||||||
"createButton": "Create",
|
"createButton": "Create",
|
||||||
"noData": "No ad campaigns",
|
"noData": "No ad campaigns",
|
||||||
|
"loadMore": "Load more",
|
||||||
"bonusType": {
|
"bonusType": {
|
||||||
"balance": "Balance",
|
"balance": "Balance",
|
||||||
"subscription": "Subscription",
|
"subscription": "Subscription",
|
||||||
|
|||||||
@@ -2545,6 +2545,7 @@
|
|||||||
"subtitle": "Управление рекламными ссылками",
|
"subtitle": "Управление рекламными ссылками",
|
||||||
"createButton": "Создать",
|
"createButton": "Создать",
|
||||||
"noData": "Нет рекламных кампаний",
|
"noData": "Нет рекламных кампаний",
|
||||||
|
"loadMore": "Загрузить ещё",
|
||||||
"bonusType": {
|
"bonusType": {
|
||||||
"balance": "Баланс",
|
"balance": "Баланс",
|
||||||
"subscription": "Подписка",
|
"subscription": "Подписка",
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
import { campaignsApi, CampaignListItem, CampaignBonusType } from '../api/campaigns';
|
import { campaignsApi, CampaignListItem, CampaignBonusType } from '../api/campaigns';
|
||||||
import { PlusIcon, EditIcon, TrashIcon, CheckIcon, XIcon, ChartIcon } from '../components/icons';
|
import { PlusIcon, EditIcon, TrashIcon, CheckIcon, XIcon, ChartIcon } from '../components/icons';
|
||||||
import { usePlatform } from '../platform/hooks/usePlatform';
|
import { usePlatform } from '../platform/hooks/usePlatform';
|
||||||
|
|
||||||
|
const PAGE_SIZE = 50;
|
||||||
|
|
||||||
// Bonus type labels and colors
|
// Bonus type labels and colors
|
||||||
const bonusTypeConfig: Record<
|
const bonusTypeConfig: Record<
|
||||||
CampaignBonusType,
|
CampaignBonusType,
|
||||||
@@ -69,9 +71,20 @@ export default function AdminCampaigns() {
|
|||||||
const [deleteConfirm, setDeleteConfirm] = useState<number | null>(null);
|
const [deleteConfirm, setDeleteConfirm] = useState<number | null>(null);
|
||||||
|
|
||||||
// Queries
|
// Queries
|
||||||
const { data: campaignsData, isLoading } = useQuery({
|
const {
|
||||||
|
data: campaignsData,
|
||||||
|
isLoading,
|
||||||
|
hasNextPage,
|
||||||
|
fetchNextPage,
|
||||||
|
isFetchingNextPage,
|
||||||
|
} = useInfiniteQuery({
|
||||||
queryKey: ['admin-campaigns'],
|
queryKey: ['admin-campaigns'],
|
||||||
queryFn: () => campaignsApi.getCampaigns(true),
|
queryFn: ({ pageParam = 0 }) => campaignsApi.getCampaigns(true, pageParam, PAGE_SIZE),
|
||||||
|
initialPageParam: 0,
|
||||||
|
getNextPageParam: (lastPage, allPages) => {
|
||||||
|
const loaded = allPages.reduce((sum, p) => sum + p.campaigns.length, 0);
|
||||||
|
return loaded < lastPage.total ? loaded : undefined;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: overview } = useQuery({
|
const { data: overview } = useQuery({
|
||||||
@@ -96,7 +109,7 @@ export default function AdminCampaigns() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const campaigns = campaignsData?.campaigns || [];
|
const campaigns = campaignsData?.pages.flatMap((p) => p.campaigns) ?? [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="animate-fade-in">
|
<div className="animate-fade-in">
|
||||||
@@ -261,6 +274,21 @@ export default function AdminCampaigns() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
{/* Load more */}
|
||||||
|
{hasNextPage && (
|
||||||
|
<button
|
||||||
|
onClick={() => fetchNextPage()}
|
||||||
|
disabled={isFetchingNextPage}
|
||||||
|
className="flex w-full items-center justify-center gap-2 rounded-xl border border-dark-700 bg-dark-800 py-3 text-sm font-medium text-dark-300 transition-colors hover:border-dark-600 hover:text-dark-100 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{isFetchingNextPage ? (
|
||||||
|
<div className="h-4 w-4 animate-spin rounded-full border-2 border-dark-500 border-t-accent-500" />
|
||||||
|
) : (
|
||||||
|
t('admin.campaigns.loadMore', 'Load more')
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user