/** * Data Completeness Table Component * * Virtualized table displaying entity completeness data with sorting and actions */ import { useMemo } from 'react'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Badge } from '@/components/ui/badge'; import { Progress } from '@/components/ui/progress'; import { Button } from '@/components/ui/button'; import { ExternalLink, AlertCircle } from 'lucide-react'; import { Link } from 'react-router-dom'; import type { EntityCompleteness, CompletenessFilters } from '@/types/data-completeness'; import { formatDistanceToNow } from 'date-fns'; interface CompletenessTableProps { entities: EntityCompleteness[]; filters: CompletenessFilters; } export function CompletenessTable({ entities, filters }: CompletenessTableProps) { // Filter and sort entities const filteredEntities = useMemo(() => { let filtered = entities; // Apply search filter if (filters.searchQuery) { const query = filters.searchQuery.toLowerCase(); filtered = filtered.filter((entity) => entity.name.toLowerCase().includes(query) ); } // Sort by completeness score (ascending - most incomplete first) return filtered.sort((a, b) => a.completeness_score - b.completeness_score); }, [entities, filters]); const getEntityUrl = (entity: EntityCompleteness) => { switch (entity.entity_type) { case 'park': return `/parks/${entity.slug}`; case 'ride': return `/rides/${entity.slug}`; case 'company': return `/companies/${entity.slug}`; case 'ride_model': return `/ride-models/${entity.slug}`; default: return '#'; } }; const getScoreColor = (score: number) => { if (score >= 80) return 'text-green-600'; if (score >= 50) return 'text-yellow-600'; return 'text-destructive'; }; const getMissingFieldsCount = (entity: EntityCompleteness) => { return ( entity.missing_fields.critical.length + entity.missing_fields.important.length + entity.missing_fields.valuable.length + entity.missing_fields.supplementary.length ); }; if (filteredEntities.length === 0) { return (

No entities found

Try adjusting your filters

); } return (
Entity Type Completeness Missing Fields Last Updated Actions {filteredEntities.map((entity) => ( {entity.name} {entity.entity_type.replace('_', ' ')}
{entity.completeness_score.toFixed(1)}%
{entity.missing_fields.critical.length > 0 && ( {entity.missing_fields.critical.length} Critical )} {entity.missing_fields.important.length > 0 && ( {entity.missing_fields.important.length} Important )} {getMissingFieldsCount(entity) === 0 && ( Complete )}
{formatDistanceToNow(new Date(entity.updated_at), { addSuffix: true })}
))}
); }