mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 14:11:13 -05:00
feat: Implement Sprint 3 Performance Optimizations
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { logger } from '@/lib/logger';
|
||||
@@ -38,15 +39,21 @@ export interface ModerationActions {
|
||||
export function useModerationActions(config: ModerationActionsConfig): ModerationActions {
|
||||
const { user, onActionStart, onActionComplete } = config;
|
||||
const { toast } = useToast();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
/**
|
||||
* Perform moderation action (approve/reject)
|
||||
* Perform moderation action (approve/reject) with optimistic updates
|
||||
*/
|
||||
const performAction = useCallback(
|
||||
async (item: ModerationItem, action: 'approved' | 'rejected', moderatorNotes?: string) => {
|
||||
onActionStart(item.id);
|
||||
|
||||
try {
|
||||
const performActionMutation = useMutation({
|
||||
mutationFn: async ({
|
||||
item,
|
||||
action,
|
||||
moderatorNotes
|
||||
}: {
|
||||
item: ModerationItem;
|
||||
action: 'approved' | 'rejected';
|
||||
moderatorNotes?: string;
|
||||
}) => {
|
||||
// Handle photo submissions
|
||||
if (action === 'approved' && item.submission_type === 'photo') {
|
||||
const { data: photoSubmission, error: fetchError } = await supabase
|
||||
@@ -263,20 +270,73 @@ export function useModerationActions(config: ModerationActionsConfig): Moderatio
|
||||
description: `The ${item.type} has been ${action}`,
|
||||
});
|
||||
|
||||
logger.log(`✅ Action ${action} completed for ${item.id}`);
|
||||
} catch (error: unknown) {
|
||||
logger.error('❌ Error performing action:', { error: getErrorMessage(error) });
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: getErrorMessage(error) || `Failed to ${action} content`,
|
||||
variant: 'destructive',
|
||||
});
|
||||
throw error;
|
||||
} finally {
|
||||
onActionComplete();
|
||||
}
|
||||
logger.log(`✅ Action ${action} completed for ${item.id}`);
|
||||
return { item, action };
|
||||
},
|
||||
[user, toast, onActionStart, onActionComplete]
|
||||
onMutate: async ({ item, action }) => {
|
||||
// Cancel outgoing refetches
|
||||
await queryClient.cancelQueries({ queryKey: ['moderation-queue'] });
|
||||
|
||||
// Snapshot previous value
|
||||
const previousData = queryClient.getQueryData(['moderation-queue']);
|
||||
|
||||
// Optimistically update cache
|
||||
queryClient.setQueriesData({ queryKey: ['moderation-queue'] }, (old: any) => {
|
||||
if (!old?.submissions) return old;
|
||||
|
||||
return {
|
||||
...old,
|
||||
submissions: old.submissions.map((i: ModerationItem) =>
|
||||
i.id === item.id
|
||||
? {
|
||||
...i,
|
||||
status: action,
|
||||
_optimistic: true,
|
||||
reviewed_at: new Date().toISOString(),
|
||||
reviewer_id: user?.id,
|
||||
}
|
||||
: i
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
return { previousData };
|
||||
},
|
||||
onError: (error, variables, context) => {
|
||||
// Rollback on error
|
||||
if (context?.previousData) {
|
||||
queryClient.setQueryData(['moderation-queue'], context.previousData);
|
||||
}
|
||||
|
||||
logger.error('❌ Error performing action:', { error: getErrorMessage(error) });
|
||||
toast({
|
||||
title: 'Action Failed',
|
||||
description: getErrorMessage(error) || `Failed to ${variables.action} content`,
|
||||
variant: 'destructive',
|
||||
});
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
toast({
|
||||
title: `Content ${data.action}`,
|
||||
description: `The ${data.item.type} has been ${data.action}`,
|
||||
});
|
||||
},
|
||||
onSettled: () => {
|
||||
// Always refetch to ensure consistency
|
||||
queryClient.invalidateQueries({ queryKey: ['moderation-queue'] });
|
||||
onActionComplete();
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Wrapper for performAction mutation to maintain API compatibility
|
||||
*/
|
||||
const performAction = useCallback(
|
||||
async (item: ModerationItem, action: 'approved' | 'rejected', moderatorNotes?: string) => {
|
||||
onActionStart(item.id);
|
||||
await performActionMutation.mutateAsync({ item, action, moderatorNotes });
|
||||
},
|
||||
[onActionStart, performActionMutation]
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user