Skip to main content

useAdminSponsorAds

Overview

useAdminSponsorAds is a React hook for managing sponsor advertisements in the admin panel. It provides a full moderation workflow (approve, reject, cancel), deletion, paginated listing with multi-field filtering and sorting, aggregate statistics, and automatic cache invalidation. Built on top of TanStack React Query with keepPreviousData for seamless pagination transitions.

Source: template/hooks/use-admin-sponsor-ads.ts

Signature / Parameters

function useAdminSponsorAds(
options?: UseAdminSponsorAdsOptions
): UseAdminSponsorAdsReturn

UseAdminSponsorAdsOptions

ParameterTypeDefaultDescription
pagenumber1Initial page number for pagination
limitnumber10Number of sponsor ads per page
statusSponsorAdStatusundefinedFilter by ad status
intervalSponsorAdIntervalTypeundefinedFilter by billing interval type
searchstringundefinedSearch term to filter sponsor ads
sortBySponsorAdSortBy'createdAt'Field to sort results by
sortOrder'asc' | 'desc''desc'Sort direction

SponsorAdSortBy

type SponsorAdSortBy = 'createdAt' | 'updatedAt' | 'startDate' | 'endDate' | 'status';

Return Values

The hook returns an object implementing UseAdminSponsorAdsReturn:

Data

PropertyTypeDescription
sponsorAdsSponsorAd[]Array of sponsor ads for the current page
statsSponsorAdStats | nullAggregate statistics across all sponsor ads

Loading States

PropertyTypeDescription
isLoadingbooleantrue only on initial load (no cached data)
isSubmittingbooleantrue when any mutation (approve/reject/cancel/delete) is pending

Pagination

PropertyTypeDescription
currentPagenumberCurrent page number
totalPagesnumberTotal number of pages (defaults to 1)
totalItemsnumberTotal number of sponsor ads

Sorting

PropertyTypeDescription
sortBySponsorAdSortByCurrent sort field
sortOrder'asc' | 'desc'Current sort direction

Actions

MethodSignatureDescription
approveSponsorAd(id: string, forceApprove?: boolean) => Promise<{ success: boolean; requiresForceApprove?: boolean }>Approve a sponsor ad. Returns requiresForceApprove: true if payment not received.
rejectSponsorAd(id: string, reason: string) => Promise<boolean>Reject a sponsor ad with a reason.
cancelSponsorAd(id: string, reason?: string) => Promise<boolean>Cancel an active sponsor ad with an optional reason.
deleteSponsorAd(id: string) => Promise<boolean>Permanently delete a sponsor ad.

Setters

MethodSignatureDescription
setSortBy(sortBy: SponsorAdSortBy) => voidChange sort field (resets page to 1)
setSortOrder(order: 'asc' | 'desc') => voidChange sort direction (resets page to 1)
setCurrentPage(page: number) => voidNavigate to a specific page

Utility

MethodSignatureDescription
refreshData() => voidInvalidate all sponsor-ads queries for a refetch

Implementation Details

  • Query caching: Uses TanStack React Query with a 2-minute staleTime and 5-minute gcTime -- shorter than most admin hooks due to the time-sensitive nature of ad approvals.
  • Placeholder data: Uses keepPreviousData for seamless pagination transitions.
  • Immediate refetch: After mutations, the hook uses refetchQueries instead of invalidateQueries to ensure the UI updates immediately rather than waiting for the next natural refetch.
  • Payment verification: The approveSponsorAd action supports a two-step approval flow. If payment has not been received, the API returns PAYMENT_NOT_RECEIVED and the hook returns { success: false, requiresForceApprove: true }, allowing the UI to prompt for force-approval confirmation.
  • Sort-resets pagination: Changing sortBy or sortOrder automatically resets currentPage to 1.
  • Page sync: The hook syncs the internal currentPage state with the external page option prop via useEffect, so that parent-level filter changes that reset the page are reflected.
  • Toast notifications: All mutation success and error states trigger sonner toast notifications automatically, except for the PAYMENT_NOT_RECEIVED error which is handled silently for UI-level handling.
  • Memoized params: Query parameters are memoized with useMemo to prevent unnecessary re-renders and query refetches.

Query Keys

const sponsorAdsQueryKeys = {
all: ['sponsor-ads'],
lists: () => ['sponsor-ads', 'list'],
list: (filters) => ['sponsor-ads', 'list', filters],
details: () => ['sponsor-ads', 'detail'],
detail: (id) => ['sponsor-ads', 'detail', id],
};

API Endpoints

OperationMethodEndpoint
ListGET/api/admin/sponsor-ads
ApprovePOST/api/admin/sponsor-ads/:id/approve
RejectPOST/api/admin/sponsor-ads/:id/reject
CancelPOST/api/admin/sponsor-ads/:id/cancel
DeleteDELETE/api/admin/sponsor-ads/:id

Usage Examples

Paginated listing with filters

import { useAdminSponsorAds } from '@/hooks/use-admin-sponsor-ads';

function SponsorAdsPage() {
const {
sponsorAds,
stats,
totalItems,
totalPages,
currentPage,
setCurrentPage,
isLoading,
} = useAdminSponsorAds({
limit: 20,
status: 'pending',
sortBy: 'createdAt',
sortOrder: 'desc',
});

if (isLoading) return <Spinner />;

return (
<div>
<StatsBar stats={stats} />
<p>{totalItems} sponsor ads</p>
<SponsorAdsTable ads={sponsorAds} />
<Pagination
current={currentPage}
total={totalPages}
onChange={setCurrentPage}
/>
</div>
);
}

Approval workflow with force-approve

const { approveSponsorAd, isSubmitting } = useAdminSponsorAds();

const handleApprove = async (adId: string) => {
const result = await approveSponsorAd(adId);

if (result.requiresForceApprove) {
// Payment not received -- prompt admin for confirmation
const confirmed = window.confirm(
'Payment has not been received. Force approve anyway?'
);
if (confirmed) {
await approveSponsorAd(adId, true);
}
}
};

Rejection and cancellation

const { rejectSponsorAd, cancelSponsorAd } = useAdminSponsorAds();

// Reject a pending ad
const handleReject = async (adId: string) => {
const success = await rejectSponsorAd(adId, 'Content violates guidelines');
};

// Cancel an active ad
const handleCancel = async (adId: string) => {
const success = await cancelSponsorAd(adId, 'Advertiser requested cancellation');
};

Dynamic sorting

const { sponsorAds, sortBy, sortOrder, setSortBy, setSortOrder } =
useAdminSponsorAds();

function SortableHeader({ field, label }: { field: SponsorAdSortBy; label: string }) {
return (
<th
onClick={() => {
if (sortBy === field) {
setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc');
} else {
setSortBy(field);
}
}}
>
{label} {sortBy === field && (sortOrder === 'asc' ? '↑' : '↓')}
</th>
);
}
  • useAdminItems -- Item management with a similar approve/reject workflow.
  • useAdminStats -- Platform-wide statistics including ad metrics.
  • useAdminFilters -- Unified filter state management for admin panels.