mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 10:31:13 -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
146 lines
4.8 KiB
TypeScript
146 lines
4.8 KiB
TypeScript
/**
|
|
* Data Completeness Dashboard
|
|
*
|
|
* Main dashboard component combining summary, filters, and table
|
|
* Provides comprehensive view of data quality across all entity types
|
|
*/
|
|
|
|
import { useState, useMemo } from 'react';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
|
import { Loader2, AlertCircle, RefreshCw } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { useDataCompleteness } from '@/hooks/useDataCompleteness';
|
|
import { CompletenessSummary } from './CompletenesSummary';
|
|
import { CompletenessFilters } from './CompletenessFilters';
|
|
import { CompletenessTable } from './CompletenessTable';
|
|
import type { CompletenessFilters as Filters, EntityType } from '@/types/data-completeness';
|
|
|
|
export function DataCompletenessDashboard() {
|
|
const [filters, setFilters] = useState<Filters>({});
|
|
const { data, isLoading, error, refetch, isRefetching } = useDataCompleteness(filters);
|
|
|
|
// Combine all entities for the "All" tab
|
|
const allEntities = useMemo(() => {
|
|
if (!data) return [];
|
|
return [
|
|
...data.entities.parks,
|
|
...data.entities.rides,
|
|
...data.entities.companies,
|
|
...data.entities.ride_models,
|
|
];
|
|
}, [data]);
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="flex items-center justify-center py-12">
|
|
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
|
<span className="ml-2 text-muted-foreground">Analyzing data completeness...</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<Alert variant="destructive">
|
|
<AlertCircle className="h-4 w-4" />
|
|
<AlertDescription>
|
|
Failed to load data completeness analysis. Please try again.
|
|
</AlertDescription>
|
|
</Alert>
|
|
);
|
|
}
|
|
|
|
if (!data) return null;
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-3xl font-bold">Data Completeness Dashboard</h1>
|
|
<p className="text-muted-foreground">
|
|
Monitor and improve data quality across all entities
|
|
</p>
|
|
</div>
|
|
<Button
|
|
onClick={() => refetch()}
|
|
disabled={isRefetching}
|
|
variant="outline"
|
|
>
|
|
{isRefetching ? (
|
|
<Loader2 className="h-4 w-4 animate-spin mr-2" />
|
|
) : (
|
|
<RefreshCw className="h-4 w-4 mr-2" />
|
|
)}
|
|
Refresh
|
|
</Button>
|
|
</div>
|
|
|
|
<CompletenessSummary summary={data.summary} />
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Filter Entities</CardTitle>
|
|
<CardDescription>
|
|
Filter by entity type, completeness score, and missing field categories
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<CompletenessFilters filters={filters} onFiltersChange={setFilters} />
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Entity Details</CardTitle>
|
|
<CardDescription>
|
|
Entities sorted by completeness (most incomplete first)
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Tabs defaultValue="all" className="space-y-4">
|
|
<TabsList>
|
|
<TabsTrigger value="all">
|
|
All ({allEntities.length})
|
|
</TabsTrigger>
|
|
<TabsTrigger value="parks">
|
|
Parks ({data.entities.parks.length})
|
|
</TabsTrigger>
|
|
<TabsTrigger value="rides">
|
|
Rides ({data.entities.rides.length})
|
|
</TabsTrigger>
|
|
<TabsTrigger value="companies">
|
|
Companies ({data.entities.companies.length})
|
|
</TabsTrigger>
|
|
<TabsTrigger value="ride_models">
|
|
Ride Models ({data.entities.ride_models.length})
|
|
</TabsTrigger>
|
|
</TabsList>
|
|
|
|
<TabsContent value="all">
|
|
<CompletenessTable entities={allEntities} filters={filters} />
|
|
</TabsContent>
|
|
|
|
<TabsContent value="parks">
|
|
<CompletenessTable entities={data.entities.parks} filters={filters} />
|
|
</TabsContent>
|
|
|
|
<TabsContent value="rides">
|
|
<CompletenessTable entities={data.entities.rides} filters={filters} />
|
|
</TabsContent>
|
|
|
|
<TabsContent value="companies">
|
|
<CompletenessTable entities={data.entities.companies} filters={filters} />
|
|
</TabsContent>
|
|
|
|
<TabsContent value="ride_models">
|
|
<CompletenessTable entities={data.entities.ride_models} filters={filters} />
|
|
</TabsContent>
|
|
</Tabs>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|