mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 23:11:12 -05:00
feat: Implement admin component optimizations
This commit is contained in:
98
src/hooks/admin/useVersionAudit.ts
Normal file
98
src/hooks/admin/useVersionAudit.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { queryKeys } from '@/lib/queryKeys';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useUserRole } from '@/hooks/useUserRole';
|
||||
|
||||
/**
|
||||
* useVersionAudit Hook
|
||||
*
|
||||
* Detects suspicious entity versions without user attribution for security monitoring.
|
||||
*
|
||||
* Features:
|
||||
* - Combines 4 count queries with Promise.all() for parallel execution
|
||||
* - Caches for 5 minutes (security alert, should be relatively fresh)
|
||||
* - Returns total count + breakdown by entity type
|
||||
* - Only runs for moderators/admins
|
||||
* - Performance monitoring with slow query warnings
|
||||
*
|
||||
* @returns TanStack Query result with audit data
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const { data: auditResult, isLoading } = useVersionAudit();
|
||||
*
|
||||
* if (auditResult && auditResult.totalCount > 0) {
|
||||
* console.warn(`Found ${auditResult.totalCount} suspicious versions`);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
|
||||
interface VersionAuditResult {
|
||||
totalCount: number;
|
||||
parkVersions: number;
|
||||
rideVersions: number;
|
||||
companyVersions: number;
|
||||
modelVersions: number;
|
||||
}
|
||||
|
||||
export function useVersionAudit() {
|
||||
const { user } = useAuth();
|
||||
const { isModerator } = useUserRole();
|
||||
|
||||
return useQuery<VersionAuditResult>({
|
||||
queryKey: queryKeys.admin.versionAudit,
|
||||
queryFn: async () => {
|
||||
const startTime = performance.now();
|
||||
|
||||
const [parksResult, ridesResult, companiesResult, modelsResult] = await Promise.all([
|
||||
supabase
|
||||
.from('park_versions')
|
||||
.select('*', { count: 'exact', head: true })
|
||||
.is('created_by', null),
|
||||
supabase
|
||||
.from('ride_versions')
|
||||
.select('*', { count: 'exact', head: true })
|
||||
.is('created_by', null),
|
||||
supabase
|
||||
.from('company_versions')
|
||||
.select('*', { count: 'exact', head: true })
|
||||
.is('created_by', null),
|
||||
supabase
|
||||
.from('ride_model_versions')
|
||||
.select('*', { count: 'exact', head: true })
|
||||
.is('created_by', null),
|
||||
]);
|
||||
|
||||
// Check for errors
|
||||
if (parksResult.error) throw parksResult.error;
|
||||
if (ridesResult.error) throw ridesResult.error;
|
||||
if (companiesResult.error) throw companiesResult.error;
|
||||
if (modelsResult.error) throw modelsResult.error;
|
||||
|
||||
const parkCount = parksResult.count || 0;
|
||||
const rideCount = ridesResult.count || 0;
|
||||
const companyCount = companiesResult.count || 0;
|
||||
const modelCount = modelsResult.count || 0;
|
||||
|
||||
const duration = performance.now() - startTime;
|
||||
|
||||
// Log slow queries in development
|
||||
if (import.meta.env.DEV && duration > 1000) {
|
||||
console.warn(`Slow query: useVersionAudit took ${duration}ms`);
|
||||
}
|
||||
|
||||
return {
|
||||
totalCount: parkCount + rideCount + companyCount + modelCount,
|
||||
parkVersions: parkCount,
|
||||
rideVersions: rideCount,
|
||||
companyVersions: companyCount,
|
||||
modelVersions: modelCount,
|
||||
};
|
||||
},
|
||||
enabled: !!user && isModerator(),
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
gcTime: 10 * 60 * 1000, // 10 minutes
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user