mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
perf(admin-bulk-actions): migrate users + 4 lookup loaders to React Query
User list query keys all 8 filter inputs so pagination/search/filter changes auto-refetch with proper dedup. Tariffs/promoGroups/campaigns/ partners become long-staleTime lookup queries — fired once and cached across remounts of the page. Existing setUsers/setTariffs/etc. setters stay; sync useEffects copy query.data into them so downstream selection and handler code is untouched. loadUsers becomes a thin refetch wrapper for handleRefresh and mutation handlers.
This commit is contained in:
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react'
|
|||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import {
|
import {
|
||||||
useReactTable,
|
useReactTable,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
@@ -1591,72 +1592,92 @@ export default function AdminBulkActions() {
|
|||||||
|
|
||||||
// ---- Data loading ----
|
// ---- Data loading ----
|
||||||
|
|
||||||
const loadUsers = useCallback(async () => {
|
// React Query owns network state; existing setters stay so downstream
|
||||||
try {
|
// selection / handler code does not need to change.
|
||||||
setLoading(true);
|
const usersQuery = useQuery({
|
||||||
const params: Record<string, unknown> = {
|
queryKey: [
|
||||||
|
'admin-bulk-users',
|
||||||
offset,
|
offset,
|
||||||
limit,
|
limit,
|
||||||
};
|
committedSearch,
|
||||||
|
statusFilter,
|
||||||
|
tariffFilter.join(','),
|
||||||
|
promoGroupFilter,
|
||||||
|
campaignFilter,
|
||||||
|
partnerFilter,
|
||||||
|
] as const,
|
||||||
|
queryFn: () => {
|
||||||
|
const params: Record<string, unknown> = { offset, limit };
|
||||||
if (committedSearch) params.search = committedSearch;
|
if (committedSearch) params.search = committedSearch;
|
||||||
if (statusFilter) params.subscription_status = statusFilter;
|
if (statusFilter) params.subscription_status = statusFilter;
|
||||||
if (tariffFilter.length > 0) params.tariff_id = tariffFilter.join(',');
|
if (tariffFilter.length > 0) params.tariff_id = tariffFilter.join(',');
|
||||||
if (promoGroupFilter) params.promo_group_id = Number(promoGroupFilter);
|
if (promoGroupFilter) params.promo_group_id = Number(promoGroupFilter);
|
||||||
if (campaignFilter) params.campaign_id = Number(campaignFilter);
|
if (campaignFilter) params.campaign_id = Number(campaignFilter);
|
||||||
if (partnerFilter) params.partner_id = Number(partnerFilter);
|
if (partnerFilter) params.partner_id = Number(partnerFilter);
|
||||||
|
return adminUsersApi.getUsers(params as Parameters<typeof adminUsersApi.getUsers>[0]);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const data = await adminUsersApi.getUsers(
|
useEffect(() => {
|
||||||
params as Parameters<typeof adminUsersApi.getUsers>[0],
|
if (!usersQuery.data) return;
|
||||||
);
|
setUsers(usersQuery.data.users);
|
||||||
setUsers(data.users);
|
setTotal(usersQuery.data.total);
|
||||||
setTotal(data.total);
|
|
||||||
// Auto-expand all users who have subscriptions
|
// Auto-expand all users who have subscriptions
|
||||||
const autoExpand: Record<number, boolean> = {};
|
const autoExpand: Record<number, boolean> = {};
|
||||||
for (const u of data.users) {
|
for (const u of usersQuery.data.users) {
|
||||||
if ((u.subscriptions?.length ?? 0) > 0) {
|
if ((u.subscriptions?.length ?? 0) > 0) {
|
||||||
autoExpand[u.id] = true;
|
autoExpand[u.id] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setExpandedRows(autoExpand);
|
setExpandedRows(autoExpand);
|
||||||
} catch {
|
}, [usersQuery.data]);
|
||||||
// keep stale data
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
offset,
|
|
||||||
limit,
|
|
||||||
committedSearch,
|
|
||||||
statusFilter,
|
|
||||||
tariffFilter,
|
|
||||||
promoGroupFilter,
|
|
||||||
campaignFilter,
|
|
||||||
partnerFilter,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadUsers();
|
setLoading(usersQuery.isFetching);
|
||||||
}, [loadUsers]);
|
}, [usersQuery.isFetching]);
|
||||||
|
|
||||||
|
const loadUsers = useCallback(
|
||||||
|
async () => {
|
||||||
|
await usersQuery.refetch();
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
[usersQuery.refetch],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Static lookup tables — long staleTime since these change rarely.
|
||||||
|
const tariffsLookupQuery = useQuery({
|
||||||
|
queryKey: ['admin-bulk-tariffs-lookup'] as const,
|
||||||
|
queryFn: () => tariffsApi.getTariffs(true),
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
|
});
|
||||||
|
const promoGroupsLookupQuery = useQuery({
|
||||||
|
queryKey: ['admin-bulk-promo-groups-lookup'] as const,
|
||||||
|
queryFn: () => promocodesApi.getPromoGroups({ limit: 200 }),
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
|
});
|
||||||
|
const campaignsLookupQuery = useQuery({
|
||||||
|
queryKey: ['admin-bulk-campaigns-lookup'] as const,
|
||||||
|
queryFn: () => campaignsApi.getCampaigns(true, 0, 100),
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
|
});
|
||||||
|
const partnersLookupQuery = useQuery({
|
||||||
|
queryKey: ['admin-bulk-partners-lookup'] as const,
|
||||||
|
queryFn: () => partnerApi.getPartners({ limit: 100 }),
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
|
});
|
||||||
|
|
||||||
// Load tariffs, promo groups, campaigns, and partners once (independent — one failure won't block others)
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
tariffsApi
|
if (tariffsLookupQuery.data) setTariffs(tariffsLookupQuery.data.tariffs);
|
||||||
.getTariffs(true)
|
}, [tariffsLookupQuery.data]);
|
||||||
.then((d) => setTariffs(d.tariffs))
|
useEffect(() => {
|
||||||
.catch(() => {});
|
if (promoGroupsLookupQuery.data) setPromoGroups(promoGroupsLookupQuery.data.items);
|
||||||
promocodesApi
|
}, [promoGroupsLookupQuery.data]);
|
||||||
.getPromoGroups({ limit: 200 })
|
useEffect(() => {
|
||||||
.then((d) => setPromoGroups(d.items))
|
if (campaignsLookupQuery.data) setCampaigns(campaignsLookupQuery.data.campaigns);
|
||||||
.catch(() => {});
|
}, [campaignsLookupQuery.data]);
|
||||||
campaignsApi
|
useEffect(() => {
|
||||||
.getCampaigns(true, 0, 100)
|
if (partnersLookupQuery.data) setPartners(partnersLookupQuery.data.items);
|
||||||
.then((d) => setCampaigns(d.campaigns))
|
}, [partnersLookupQuery.data]);
|
||||||
.catch(() => {});
|
|
||||||
partnerApi
|
|
||||||
.getPartners({ limit: 100 })
|
|
||||||
.then((d) => setPartners(d.items))
|
|
||||||
.catch(() => {});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// ---- Handlers ----
|
// ---- Handlers ----
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user