mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 21:11:22 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
293
src-old/hooks/moderation/useEntityCache.ts
Normal file
293
src-old/hooks/moderation/useEntityCache.ts
Normal file
@@ -0,0 +1,293 @@
|
||||
import { useRef, useCallback } from 'react';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { createTableQuery } from '@/lib/supabaseHelpers';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { MODERATION_CONSTANTS } from '@/lib/moderation/constants';
|
||||
import type { Database } from '@/integrations/supabase/types';
|
||||
|
||||
/**
|
||||
* Entity types supported by the cache
|
||||
*/
|
||||
type EntityType = 'rides' | 'parks' | 'companies';
|
||||
|
||||
/**
|
||||
* Type definitions for cached entities (can be partial)
|
||||
*/
|
||||
type Ride = Database['public']['Tables']['rides']['Row'];
|
||||
type Park = Database['public']['Tables']['parks']['Row'];
|
||||
type Company = Database['public']['Tables']['companies']['Row'];
|
||||
|
||||
/**
|
||||
* Discriminated union for all cached entity types
|
||||
*/
|
||||
type CachedEntity = Ride | Park | Company;
|
||||
|
||||
/**
|
||||
* Map entity type strings to their corresponding types
|
||||
* Cache stores partial entities with at least id and name
|
||||
*/
|
||||
interface EntityTypeMap {
|
||||
rides: Partial<Ride> & { id: string; name: string };
|
||||
parks: Partial<Park> & { id: string; name: string };
|
||||
companies: Partial<Company> & { id: string; name: string };
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache structure for entities with flexible typing
|
||||
*/
|
||||
interface EntityCacheStructure {
|
||||
rides: Map<string, Partial<Ride> & { id: string; name: string }>;
|
||||
parks: Map<string, Partial<Park> & { id: string; name: string }>;
|
||||
companies: Map<string, Partial<Company> & { id: string; name: string }>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for managing entity name caching (rides, parks, companies)
|
||||
*
|
||||
* Uses ref-based storage to avoid triggering re-renders while providing
|
||||
* efficient caching for entity lookups during moderation.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const entityCache = useEntityCache();
|
||||
*
|
||||
* // Get cached entity
|
||||
* const ride = entityCache.getCached('rides', rideId);
|
||||
*
|
||||
* // Bulk fetch and cache entities
|
||||
* await entityCache.bulkFetch('rides', [id1, id2, id3]);
|
||||
*
|
||||
* // Clear specific cache
|
||||
* entityCache.clear('rides');
|
||||
*
|
||||
* // Clear all caches
|
||||
* entityCache.clearAll();
|
||||
* ```
|
||||
*/
|
||||
export function useEntityCache() {
|
||||
// Use ref to prevent re-renders on cache updates
|
||||
const cacheRef = useRef<EntityCacheStructure>({
|
||||
rides: new Map(),
|
||||
parks: new Map(),
|
||||
companies: new Map(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a cached entity by ID with type safety
|
||||
*/
|
||||
const getCached = useCallback(<T extends EntityType>(
|
||||
type: T,
|
||||
id: string
|
||||
): EntityTypeMap[T] | undefined => {
|
||||
return cacheRef.current[type].get(id) as EntityTypeMap[T] | undefined;
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Check if an entity is cached
|
||||
*/
|
||||
const has = useCallback((type: EntityType, id: string): boolean => {
|
||||
return cacheRef.current[type].has(id);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Set a cached entity with LRU eviction and type safety
|
||||
*/
|
||||
const setCached = useCallback(<T extends EntityType>(
|
||||
type: T,
|
||||
id: string,
|
||||
data: EntityTypeMap[T]
|
||||
): void => {
|
||||
const cache = cacheRef.current[type];
|
||||
|
||||
// LRU eviction: remove oldest entry if cache is full
|
||||
if (cache.size >= MODERATION_CONSTANTS.MAX_ENTITY_CACHE_SIZE) {
|
||||
const firstKey = cache.keys().next().value;
|
||||
if (firstKey) {
|
||||
cache.delete(firstKey);
|
||||
logger.log(`♻️ [EntityCache] Evicted ${type}/${firstKey} (LRU)`);
|
||||
}
|
||||
}
|
||||
|
||||
cache.set(id, data);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Get uncached IDs from a list
|
||||
*/
|
||||
const getUncachedIds = useCallback((type: EntityType, ids: string[]): string[] => {
|
||||
return ids.filter(id => !cacheRef.current[type].has(id));
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Bulk fetch entities from the database and cache them
|
||||
* Only fetches entities that aren't already cached
|
||||
*/
|
||||
const bulkFetch = useCallback(async <T extends EntityType>(
|
||||
type: T,
|
||||
ids: string[]
|
||||
): Promise<EntityTypeMap[T][]> => {
|
||||
if (ids.length === 0) return [];
|
||||
|
||||
// Filter to only uncached IDs
|
||||
const uncachedIds = getUncachedIds(type, ids);
|
||||
if (uncachedIds.length === 0) {
|
||||
// All entities are cached, return them
|
||||
return ids.map(id => getCached(type, id)).filter((item): item is EntityTypeMap[T] => item !== undefined);
|
||||
}
|
||||
|
||||
try {
|
||||
let data: unknown[] | null = null;
|
||||
let error: unknown = null;
|
||||
|
||||
// Use type-safe table queries
|
||||
switch (type) {
|
||||
case 'rides':
|
||||
const ridesResult = await createTableQuery('rides')
|
||||
.select('id, name, slug, park_id')
|
||||
.in('id', uncachedIds);
|
||||
data = ridesResult.data;
|
||||
error = ridesResult.error;
|
||||
break;
|
||||
|
||||
case 'parks':
|
||||
const parksResult = await createTableQuery('parks')
|
||||
.select('id, name, slug')
|
||||
.in('id', uncachedIds);
|
||||
data = parksResult.data;
|
||||
error = parksResult.error;
|
||||
break;
|
||||
|
||||
case 'companies':
|
||||
const companiesResult = await createTableQuery('companies')
|
||||
.select('id, name, slug, company_type')
|
||||
.in('id', uncachedIds);
|
||||
data = companiesResult.data;
|
||||
error = companiesResult.error;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown entity type - skip
|
||||
return [];
|
||||
}
|
||||
|
||||
if (error) {
|
||||
// Silent - cache miss is acceptable
|
||||
return [];
|
||||
}
|
||||
|
||||
// Cache the fetched entities
|
||||
if (data) {
|
||||
(data as Array<Record<string, unknown>>).forEach((entity) => {
|
||||
if (entity && typeof entity === 'object' && 'id' in entity && 'name' in entity) {
|
||||
setCached(type, entity.id as string, entity as EntityTypeMap[T]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (data as EntityTypeMap[T][]) || [];
|
||||
} catch (error: unknown) {
|
||||
// Silent - cache operations are non-critical
|
||||
return [];
|
||||
}
|
||||
}, [getCached, setCached, getUncachedIds]);
|
||||
|
||||
/**
|
||||
* Fetch and cache related entities based on submission content
|
||||
* Automatically determines which entities to fetch from submission data
|
||||
*/
|
||||
const fetchRelatedEntities = useCallback(async (submissions: Array<{ content?: Record<string, string | number>; submission_type?: string }>): Promise<void> => {
|
||||
const rideIds = new Set<string>();
|
||||
const parkIds = new Set<string>();
|
||||
const companyIds = new Set<string>();
|
||||
|
||||
// Collect all entity IDs from submissions
|
||||
submissions.forEach(submission => {
|
||||
const content = submission.content;
|
||||
if (content && typeof content === 'object') {
|
||||
if (typeof content.ride_id === 'string') rideIds.add(content.ride_id);
|
||||
if (typeof content.park_id === 'string') parkIds.add(content.park_id);
|
||||
if (typeof content.company_id === 'string') companyIds.add(content.company_id);
|
||||
if (typeof content.entity_id === 'string') {
|
||||
if (submission.submission_type === 'ride') rideIds.add(content.entity_id);
|
||||
if (submission.submission_type === 'park') parkIds.add(content.entity_id);
|
||||
if (['manufacturer', 'operator', 'designer', 'property_owner'].includes(submission.submission_type || '')) {
|
||||
companyIds.add(content.entity_id);
|
||||
}
|
||||
}
|
||||
if (typeof content.manufacturer_id === 'string') companyIds.add(content.manufacturer_id);
|
||||
if (typeof content.designer_id === 'string') companyIds.add(content.designer_id);
|
||||
if (typeof content.operator_id === 'string') companyIds.add(content.operator_id);
|
||||
if (typeof content.property_owner_id === 'string') companyIds.add(content.property_owner_id);
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch all entities in parallel
|
||||
const fetchPromises: Promise<any[]>[] = [];
|
||||
|
||||
if (rideIds.size > 0) {
|
||||
fetchPromises.push(bulkFetch('rides', Array.from(rideIds)));
|
||||
}
|
||||
if (parkIds.size > 0) {
|
||||
fetchPromises.push(bulkFetch('parks', Array.from(parkIds)));
|
||||
}
|
||||
if (companyIds.size > 0) {
|
||||
fetchPromises.push(bulkFetch('companies', Array.from(companyIds)));
|
||||
}
|
||||
|
||||
await Promise.all(fetchPromises);
|
||||
}, [bulkFetch]);
|
||||
|
||||
/**
|
||||
* Clear a specific entity type cache
|
||||
*/
|
||||
const clear = useCallback((type: EntityType): void => {
|
||||
cacheRef.current[type].clear();
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Clear all entity caches
|
||||
*/
|
||||
const clearAll = useCallback((): void => {
|
||||
cacheRef.current.rides.clear();
|
||||
cacheRef.current.parks.clear();
|
||||
cacheRef.current.companies.clear();
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Get cache size for a specific type
|
||||
*/
|
||||
const getSize = useCallback((type: EntityType): number => {
|
||||
return cacheRef.current[type].size;
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Get total cache size across all entity types
|
||||
*/
|
||||
const getTotalSize = useCallback((): number => {
|
||||
return cacheRef.current.rides.size +
|
||||
cacheRef.current.parks.size +
|
||||
cacheRef.current.companies.size;
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Get direct access to cache ref (for advanced use cases)
|
||||
* Use with caution - prefer using the provided methods
|
||||
*/
|
||||
const getCacheRef = useCallback(() => cacheRef.current, []);
|
||||
|
||||
// Return without useMemo wrapper (OPTIMIZED)
|
||||
return {
|
||||
getCached,
|
||||
has,
|
||||
setCached,
|
||||
getUncachedIds,
|
||||
bulkFetch,
|
||||
fetchRelatedEntities,
|
||||
clear,
|
||||
clearAll,
|
||||
getSize,
|
||||
getTotalSize,
|
||||
getCacheRef,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user