mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 11:31:11 -05:00
Adds comprehensive data completeness dashboard UI and hooks: - Introduces data completeness types and hook (useDataCompleteness) to fetch and subscribe to updates - Builds dashboard components (summary, filters, table) and integrates into Admin Settings - Wireframes for real-time updates and filtering across parks, rides, companies, and ride models - Integrates into AdminSettings with a new Data Quality tab and route - Adds data types and scaffolding for analytics, including completeness analysis structure
107 lines
3.1 KiB
TypeScript
107 lines
3.1 KiB
TypeScript
/**
|
|
* Data Completeness Hook
|
|
*
|
|
* React Query hook for fetching and caching data completeness analysis
|
|
* with real-time updates via Supabase subscriptions
|
|
*/
|
|
|
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
import { supabase } from '@/integrations/supabase/client';
|
|
import { useEffect } from 'react';
|
|
import type { CompletenessAnalysis, CompletenessFilters } from '@/types/data-completeness';
|
|
import { handleError } from '@/lib/errorHandler';
|
|
|
|
export function useDataCompleteness(filters: CompletenessFilters = {}) {
|
|
const queryClient = useQueryClient();
|
|
|
|
const query = useQuery({
|
|
queryKey: ['data-completeness', filters],
|
|
queryFn: async (): Promise<CompletenessAnalysis> => {
|
|
try {
|
|
const { data, error } = await supabase.rpc('analyze_data_completeness', {
|
|
p_entity_type: filters.entityType ?? undefined,
|
|
p_min_score: filters.minScore ?? undefined,
|
|
p_max_score: filters.maxScore ?? undefined,
|
|
p_missing_category: filters.missingCategory ?? undefined,
|
|
p_limit: 1000,
|
|
p_offset: 0,
|
|
});
|
|
|
|
if (error) throw error;
|
|
|
|
return data as unknown as CompletenessAnalysis;
|
|
} catch (error) {
|
|
handleError(error, {
|
|
action: 'fetch_data_completeness',
|
|
metadata: {
|
|
filters,
|
|
},
|
|
});
|
|
throw error;
|
|
}
|
|
},
|
|
staleTime: 5 * 60 * 1000, // Cache for 5 minutes
|
|
refetchOnWindowFocus: false,
|
|
});
|
|
|
|
// Real-time subscriptions for data updates
|
|
useEffect(() => {
|
|
// Subscribe to parks changes
|
|
const parksChannel = supabase
|
|
.channel('parks-completeness-updates')
|
|
.on(
|
|
'postgres_changes',
|
|
{ event: '*', schema: 'public', table: 'parks' },
|
|
() => {
|
|
queryClient.invalidateQueries({ queryKey: ['data-completeness'] });
|
|
}
|
|
)
|
|
.subscribe();
|
|
|
|
// Subscribe to rides changes
|
|
const ridesChannel = supabase
|
|
.channel('rides-completeness-updates')
|
|
.on(
|
|
'postgres_changes',
|
|
{ event: '*', schema: 'public', table: 'rides' },
|
|
() => {
|
|
queryClient.invalidateQueries({ queryKey: ['data-completeness'] });
|
|
}
|
|
)
|
|
.subscribe();
|
|
|
|
// Subscribe to companies changes
|
|
const companiesChannel = supabase
|
|
.channel('companies-completeness-updates')
|
|
.on(
|
|
'postgres_changes',
|
|
{ event: '*', schema: 'public', table: 'companies' },
|
|
() => {
|
|
queryClient.invalidateQueries({ queryKey: ['data-completeness'] });
|
|
}
|
|
)
|
|
.subscribe();
|
|
|
|
// Subscribe to ride_models changes
|
|
const modelsChannel = supabase
|
|
.channel('ride-models-completeness-updates')
|
|
.on(
|
|
'postgres_changes',
|
|
{ event: '*', schema: 'public', table: 'ride_models' },
|
|
() => {
|
|
queryClient.invalidateQueries({ queryKey: ['data-completeness'] });
|
|
}
|
|
)
|
|
.subscribe();
|
|
|
|
return () => {
|
|
supabase.removeChannel(parksChannel);
|
|
supabase.removeChannel(ridesChannel);
|
|
supabase.removeChannel(companiesChannel);
|
|
supabase.removeChannel(modelsChannel);
|
|
};
|
|
}, [queryClient]);
|
|
|
|
return query;
|
|
}
|