mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 17:51:14 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
225
src-old/hooks/moderation/useQueueQuery.ts
Normal file
225
src-old/hooks/moderation/useQueueQuery.ts
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* TanStack Query hook for moderation queue data fetching
|
||||
*
|
||||
* Wraps the existing fetchSubmissions query builder with React Query
|
||||
* to provide automatic caching, deduplication, and background refetching.
|
||||
*/
|
||||
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { fetchSubmissions, type QueryConfig } from '@/lib/moderation/queries';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { MODERATION_CONSTANTS } from '@/lib/moderation/constants';
|
||||
import { validateModerationItems } from '@/lib/moderation/validation';
|
||||
import type {
|
||||
ModerationItem,
|
||||
EntityFilter,
|
||||
StatusFilter,
|
||||
QueueTab,
|
||||
SortField,
|
||||
SortDirection
|
||||
} from '@/types/moderation';
|
||||
|
||||
/**
|
||||
* Get specific, actionable error message based on error type
|
||||
*/
|
||||
function getSpecificErrorMessage(error: unknown): string {
|
||||
// Offline detection
|
||||
if (!navigator.onLine) {
|
||||
return 'You appear to be offline. Check your internet connection and try again.';
|
||||
}
|
||||
|
||||
// Timeout
|
||||
if (error instanceof Error && error.name === 'AbortError') {
|
||||
return 'Request timed out. The server is taking too long to respond. Please try again.';
|
||||
}
|
||||
|
||||
// Check for Supabase-specific errors
|
||||
if (typeof error === 'object' && error !== null) {
|
||||
const err = error as any;
|
||||
|
||||
// 500 errors
|
||||
if (err.status === 500 || err.code === '500') {
|
||||
return 'Server error occurred. Our team has been notified. Please try again in a few minutes.';
|
||||
}
|
||||
|
||||
// 429 Rate limiting
|
||||
if (err.status === 429 || err.message?.includes('rate limit')) {
|
||||
return 'Too many requests. Please wait a moment before trying again.';
|
||||
}
|
||||
|
||||
// Authentication errors
|
||||
if (err.status === 401 || err.message?.includes('JWT')) {
|
||||
return 'Your session has expired. Please refresh the page and sign in again.';
|
||||
}
|
||||
|
||||
// Permission errors
|
||||
if (err.status === 403 || err.message?.includes('permission')) {
|
||||
return 'You do not have permission to access the moderation queue.';
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
return getErrorMessage(error) || 'Failed to load moderation queue. Please try again.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for queue query
|
||||
*/
|
||||
export interface UseQueueQueryConfig {
|
||||
/** User making the query */
|
||||
userId: string | undefined;
|
||||
|
||||
/** Whether user is admin */
|
||||
isAdmin: boolean;
|
||||
|
||||
/** Whether user is superuser */
|
||||
isSuperuser: boolean;
|
||||
|
||||
/** Entity filter */
|
||||
entityFilter: EntityFilter;
|
||||
|
||||
/** Status filter */
|
||||
statusFilter: StatusFilter;
|
||||
|
||||
/** Active tab */
|
||||
tab: QueueTab;
|
||||
|
||||
/** Current page */
|
||||
currentPage: number;
|
||||
|
||||
/** Page size */
|
||||
pageSize: number;
|
||||
|
||||
/** Sort configuration */
|
||||
sortConfig: {
|
||||
field: SortField;
|
||||
direction: SortDirection;
|
||||
};
|
||||
|
||||
/** Whether query is enabled (defaults to true) */
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return type for useQueueQuery
|
||||
*/
|
||||
export interface UseQueueQueryReturn {
|
||||
/** Queue items */
|
||||
items: ModerationItem[];
|
||||
|
||||
/** Total count of items matching filters */
|
||||
totalCount: number;
|
||||
|
||||
/** Initial loading state (no data yet) */
|
||||
isLoading: boolean;
|
||||
|
||||
/** Background refresh in progress (has data already) */
|
||||
isRefreshing: boolean;
|
||||
|
||||
/** Any error that occurred */
|
||||
error: Error | null;
|
||||
|
||||
/** Manually trigger a refetch */
|
||||
refetch: () => Promise<any>;
|
||||
|
||||
/** Invalidate this query (triggers background refetch) */
|
||||
invalidate: () => Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to fetch moderation queue data using TanStack Query
|
||||
*/
|
||||
export function useQueueQuery(config: UseQueueQueryConfig): UseQueueQueryReturn {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// Build query config for fetchSubmissions
|
||||
const queryConfig: QueryConfig = {
|
||||
userId: config.userId || '',
|
||||
isAdmin: config.isAdmin,
|
||||
isSuperuser: config.isSuperuser,
|
||||
entityFilter: config.entityFilter,
|
||||
statusFilter: config.statusFilter,
|
||||
tab: config.tab,
|
||||
currentPage: config.currentPage,
|
||||
pageSize: config.pageSize,
|
||||
sortConfig: config.sortConfig,
|
||||
};
|
||||
|
||||
// Create stable query key (TanStack Query uses this for caching/deduplication)
|
||||
// Include user context to ensure proper cache isolation per user/role
|
||||
const queryKey = [
|
||||
'moderation-queue',
|
||||
config.userId,
|
||||
config.isAdmin,
|
||||
config.isSuperuser,
|
||||
config.entityFilter,
|
||||
config.statusFilter,
|
||||
config.tab,
|
||||
config.currentPage,
|
||||
config.pageSize,
|
||||
config.sortConfig.field,
|
||||
config.sortConfig.direction,
|
||||
];
|
||||
|
||||
// Execute query
|
||||
const query = useQuery({
|
||||
queryKey,
|
||||
queryFn: async () => {
|
||||
logger.log('🔍 [TanStack Query] Fetching queue data:', queryKey);
|
||||
|
||||
// Create timeout controller (30s timeout)
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 30000);
|
||||
|
||||
try {
|
||||
const result = await fetchSubmissions(supabase, queryConfig);
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (result.error) {
|
||||
const specificMessage = getSpecificErrorMessage(result.error);
|
||||
// Error already captured in context
|
||||
throw new Error(specificMessage);
|
||||
}
|
||||
|
||||
// Validate data shape before returning
|
||||
const validation = validateModerationItems(result.submissions);
|
||||
if (!validation.success) {
|
||||
// Invalid data shape
|
||||
throw new Error(validation.error || 'Invalid data format');
|
||||
}
|
||||
|
||||
logger.log('✅ [TanStack Query] Fetched', validation.data!.length, 'items');
|
||||
return { ...result, submissions: validation.data! };
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
enabled: config.enabled !== false && !!config.userId,
|
||||
staleTime: MODERATION_CONSTANTS.QUERY_STALE_TIME,
|
||||
gcTime: MODERATION_CONSTANTS.QUERY_GC_TIME,
|
||||
retry: MODERATION_CONSTANTS.QUERY_RETRY_COUNT,
|
||||
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
|
||||
networkMode: 'offlineFirst', // Handle offline gracefully
|
||||
meta: {
|
||||
errorMessage: 'Failed to load moderation queue',
|
||||
},
|
||||
});
|
||||
|
||||
// Invalidate helper
|
||||
const invalidate = async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: ['moderation-queue'] });
|
||||
};
|
||||
|
||||
return {
|
||||
items: query.data?.submissions || [],
|
||||
totalCount: query.data?.totalCount || 0,
|
||||
isLoading: query.isLoading,
|
||||
isRefreshing: query.isFetching && !query.isLoading,
|
||||
error: query.error as Error | null,
|
||||
refetch: query.refetch,
|
||||
invalidate,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user