mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 21:11:12 -05:00
Fix flashing and bouncing on admin page
This commit is contained in:
@@ -1,24 +1,17 @@
|
||||
import { useState, useEffect, useImperativeHandle, forwardRef, useCallback, useRef } from 'react';
|
||||
import { CheckCircle, XCircle, Eye, Calendar, User, Filter, MessageSquare, FileText, Image, X, Trash2, ListTree, RefreshCw, AlertCircle, Clock, Lock, Unlock, AlertTriangle, UserCog, Zap } from 'lucide-react';
|
||||
import { CheckCircle, XCircle, Filter, MessageSquare, FileText, Image, X, RefreshCw, AlertCircle, Clock, Lock, Unlock, AlertTriangle, UserCog, Zap } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Card, CardContent, CardHeader } from '@/components/ui/card';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { useUserRole } from '@/hooks/useUserRole';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { format, formatDistance } from 'date-fns';
|
||||
import { formatDistance } from 'date-fns';
|
||||
import { PhotoModal } from './PhotoModal';
|
||||
import { SubmissionReviewManager } from './SubmissionReviewManager';
|
||||
import { useIsMobile } from '@/hooks/use-mobile';
|
||||
import { SubmissionChangesDisplay } from './SubmissionChangesDisplay';
|
||||
import { SubmissionItemsList } from './SubmissionItemsList';
|
||||
import { MeasurementDisplay } from '@/components/ui/measurement-display';
|
||||
import { useAdminSettings } from '@/hooks/useAdminSettings';
|
||||
import { useModerationQueue } from '@/hooks/useModerationQueue';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
@@ -27,6 +20,7 @@ import { EscalationDialog } from './EscalationDialog';
|
||||
import { ReassignDialog } from './ReassignDialog';
|
||||
import { smartMergeArray } from '@/lib/smartStateUpdate';
|
||||
import { useDebounce } from '@/hooks/useDebounce';
|
||||
import { QueueItem } from './QueueItem';
|
||||
|
||||
interface ModerationItem {
|
||||
id: string;
|
||||
@@ -816,10 +810,7 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
||||
description: `Processed ${failedItems.length} failed item(s)`,
|
||||
});
|
||||
|
||||
// Silent cleanup after delay
|
||||
setTimeout(() => {
|
||||
fetchItems(activeEntityFilter, activeStatusFilter, true);
|
||||
}, 2000);
|
||||
// No refresh needed - item already updated optimistically
|
||||
} catch (error: any) {
|
||||
console.error('Error retrying failed items:', error);
|
||||
toast({
|
||||
@@ -1404,6 +1395,34 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
||||
}
|
||||
};
|
||||
|
||||
// Memoized callbacks
|
||||
const handleNoteChange = useCallback((id: string, value: string) => {
|
||||
setNotes(prev => ({ ...prev, [id]: value }));
|
||||
}, []);
|
||||
|
||||
const handleOpenPhotos = useCallback((photos: any[], index: number) => {
|
||||
setSelectedPhotos(photos);
|
||||
setSelectedPhotoIndex(index);
|
||||
setPhotoModalOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleOpenReviewManager = useCallback((id: string) => {
|
||||
setSelectedSubmissionId(id);
|
||||
setReviewManagerOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleInteractionFocus = useCallback((id: string) => {
|
||||
setInteractingWith(prev => new Set(prev).add(id));
|
||||
}, []);
|
||||
|
||||
const handleInteractionBlur = useCallback((id: string) => {
|
||||
setInteractingWith(prev => {
|
||||
const next = new Set(prev);
|
||||
next.delete(id);
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const QueueContent = () => {
|
||||
if (isInitialLoad && loading) {
|
||||
return (
|
||||
@@ -1428,7 +1447,32 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{items.map((item) => (
|
||||
<Card
|
||||
<QueueItem
|
||||
key={item.id}
|
||||
item={item}
|
||||
isMobile={isMobile}
|
||||
actionLoading={actionLoading}
|
||||
lockedSubmissions={lockedSubmissions}
|
||||
currentLockSubmissionId={queue.currentLock?.submissionId}
|
||||
notes={notes}
|
||||
isAdmin={isAdmin()}
|
||||
isSuperuser={isSuperuser()}
|
||||
queueIsLoading={queue.isLoading}
|
||||
onNoteChange={handleNoteChange}
|
||||
onApprove={handleModerationAction}
|
||||
onResetToPending={handleResetToPending}
|
||||
onRetryFailed={handleRetryFailedItems}
|
||||
onOpenPhotos={handleOpenPhotos}
|
||||
onOpenReviewManager={handleOpenReviewManager}
|
||||
onClaimSubmission={(id) => queue.claimSubmission(id)}
|
||||
onDeleteSubmission={handleDeleteSubmission}
|
||||
onInteractionFocus={handleInteractionFocus}
|
||||
onInteractionBlur={handleInteractionBlur}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
key={item.id}
|
||||
className={`border-l-4 transition-opacity duration-200 ${
|
||||
item.status === 'flagged' ? 'border-l-red-500' :
|
||||
@@ -2424,10 +2468,8 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
||||
open={reviewManagerOpen}
|
||||
onOpenChange={setReviewManagerOpen}
|
||||
onComplete={() => {
|
||||
// Silent cleanup after delay
|
||||
setTimeout(() => {
|
||||
fetchItems(activeEntityFilter, activeStatusFilter, true);
|
||||
}, 2000);
|
||||
// No refresh needed - item was removed optimistically
|
||||
setReviewManagerOpen(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user