mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 12:51:16 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
224
src-old/hooks/moderation/useProfileCache.ts
Normal file
224
src-old/hooks/moderation/useProfileCache.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
import { useRef, useCallback } from 'react';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { MODERATION_CONSTANTS } from '@/lib/moderation/constants';
|
||||
import type { ModerationItem } from '@/types/moderation';
|
||||
|
||||
/**
|
||||
* Profile data structure returned from the database
|
||||
*/
|
||||
export interface CachedProfile {
|
||||
user_id: string;
|
||||
username: string;
|
||||
display_name?: string;
|
||||
avatar_url?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for managing user profile caching
|
||||
*
|
||||
* Uses ref-based storage to avoid triggering re-renders while providing
|
||||
* efficient caching for user profile lookups during moderation.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const profileCache = useProfileCache();
|
||||
*
|
||||
* // Get cached profile
|
||||
* const profile = profileCache.getCached(userId);
|
||||
*
|
||||
* // Bulk fetch and cache profiles
|
||||
* const profiles = await profileCache.bulkFetch([id1, id2, id3]);
|
||||
*
|
||||
* // Check if profile exists in cache
|
||||
* if (profileCache.has(userId)) {
|
||||
* const profile = profileCache.getCached(userId);
|
||||
* }
|
||||
*
|
||||
* // Clear cache
|
||||
* profileCache.clear();
|
||||
* ```
|
||||
*/
|
||||
export function useProfileCache() {
|
||||
// Use ref to prevent re-renders on cache updates
|
||||
const cacheRef = useRef<Map<string, CachedProfile>>(new Map());
|
||||
|
||||
/**
|
||||
* Get a cached profile by user ID
|
||||
*/
|
||||
const getCached = useCallback((userId: string): CachedProfile | undefined => {
|
||||
return cacheRef.current.get(userId);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Check if a profile is cached
|
||||
*/
|
||||
const has = useCallback((userId: string): boolean => {
|
||||
return cacheRef.current.has(userId);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Set a cached profile with LRU eviction
|
||||
*/
|
||||
const setCached = useCallback((userId: string, profile: CachedProfile): void => {
|
||||
const cache = cacheRef.current;
|
||||
|
||||
// LRU eviction
|
||||
if (cache.size >= MODERATION_CONSTANTS.MAX_PROFILE_CACHE_SIZE) {
|
||||
const firstKey = cache.keys().next().value;
|
||||
if (firstKey) {
|
||||
cache.delete(firstKey);
|
||||
logger.log(`♻️ [ProfileCache] Evicted ${firstKey} (LRU)`);
|
||||
}
|
||||
}
|
||||
|
||||
cache.set(userId, profile);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Get uncached user IDs from a list
|
||||
*/
|
||||
const getUncachedIds = useCallback((userIds: string[]): string[] => {
|
||||
return userIds.filter(id => !cacheRef.current.has(id));
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Bulk fetch user profiles from the database and cache them
|
||||
* Only fetches profiles that aren't already cached
|
||||
*
|
||||
* @param userIds - Array of user IDs to fetch
|
||||
* @returns Array of fetched profiles
|
||||
*/
|
||||
const bulkFetch = useCallback(async (userIds: string[]): Promise<CachedProfile[]> => {
|
||||
if (userIds.length === 0) return [];
|
||||
|
||||
// Filter to only uncached IDs
|
||||
const uncachedIds = getUncachedIds(userIds);
|
||||
if (uncachedIds.length === 0) {
|
||||
// All profiles are cached, return them
|
||||
return userIds.map(id => getCached(id)).filter((p): p is CachedProfile => !!p);
|
||||
}
|
||||
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('profiles')
|
||||
.select('user_id, username, display_name, avatar_url')
|
||||
.in('user_id', uncachedIds);
|
||||
|
||||
if (error) {
|
||||
// Silent - cache miss is acceptable
|
||||
return [];
|
||||
}
|
||||
|
||||
// Cache the fetched profiles
|
||||
if (data) {
|
||||
data.forEach((profile) => {
|
||||
const cachedProfile: CachedProfile = {
|
||||
...profile,
|
||||
display_name: profile.display_name || undefined,
|
||||
avatar_url: profile.avatar_url || undefined
|
||||
};
|
||||
setCached(profile.user_id, cachedProfile);
|
||||
});
|
||||
}
|
||||
|
||||
return (data || []).map(profile => ({
|
||||
...profile,
|
||||
display_name: profile.display_name || undefined,
|
||||
avatar_url: profile.avatar_url || undefined
|
||||
}));
|
||||
} catch (error: unknown) {
|
||||
// Silent - cache operations are non-critical
|
||||
return [];
|
||||
}
|
||||
}, [getCached, setCached, getUncachedIds]);
|
||||
|
||||
/**
|
||||
* Fetch and return profiles for a list of user IDs
|
||||
* Returns a Map for easy lookup
|
||||
*
|
||||
* @param userIds - Array of user IDs to fetch
|
||||
* @returns Map of userId -> profile
|
||||
*/
|
||||
const fetchAsMap = useCallback(async (userIds: string[]): Promise<Map<string, CachedProfile>> => {
|
||||
const profiles = await bulkFetch(userIds);
|
||||
return new Map(profiles.map(p => [p.user_id, p]));
|
||||
}, [bulkFetch]);
|
||||
|
||||
/**
|
||||
* Fetch profiles for submitters and reviewers from submissions
|
||||
* Automatically extracts user IDs and reviewer IDs from submission data
|
||||
*
|
||||
* @param submissions - Array of submissions with user_id and reviewer_id
|
||||
* @returns Map of userId -> profile for all users involved
|
||||
*/
|
||||
const fetchForSubmissions = useCallback(async (submissions: ModerationItem[]): Promise<Map<string, CachedProfile>> => {
|
||||
const userIds = submissions.map(s => s.user_id).filter(Boolean);
|
||||
const reviewerIds = submissions.map(s => s.reviewer_id).filter((id): id is string => !!id);
|
||||
const allUserIds = [...new Set([...userIds, ...reviewerIds])];
|
||||
|
||||
return await fetchAsMap(allUserIds);
|
||||
}, [fetchAsMap]);
|
||||
|
||||
/**
|
||||
* Get a display name for a user (display_name or username)
|
||||
* Returns 'Unknown User' if not found in cache
|
||||
*/
|
||||
const getDisplayName = useCallback((userId: string): string => {
|
||||
const profile = getCached(userId);
|
||||
if (!profile) return 'Unknown User';
|
||||
return profile.display_name || profile.username || 'Unknown User';
|
||||
}, [getCached]);
|
||||
|
||||
/**
|
||||
* Invalidate (remove) a specific profile from cache
|
||||
*/
|
||||
const invalidate = useCallback((userId: string): void => {
|
||||
cacheRef.current.delete(userId);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Clear all cached profiles
|
||||
*/
|
||||
const clear = useCallback((): void => {
|
||||
cacheRef.current.clear();
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Get cache size
|
||||
*/
|
||||
const getSize = useCallback((): number => {
|
||||
return cacheRef.current.size;
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Get all cached profile user IDs
|
||||
*/
|
||||
const getAllCachedIds = useCallback((): string[] => {
|
||||
return Array.from(cacheRef.current.keys());
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
fetchAsMap,
|
||||
fetchForSubmissions,
|
||||
getDisplayName,
|
||||
invalidate,
|
||||
clear,
|
||||
getSize,
|
||||
getAllCachedIds,
|
||||
getCacheRef,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user