diff --git a/src/components/moderation/EscalationDialog.tsx b/src/components/moderation/EscalationDialog.tsx index e5ae8604..4acde8d0 100644 --- a/src/components/moderation/EscalationDialog.tsx +++ b/src/components/moderation/EscalationDialog.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { AlertTriangle } from 'lucide-react'; +import { AlertTriangle, AlertCircle } from 'lucide-react'; import { Dialog, DialogContent, @@ -18,12 +18,14 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select'; +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; interface EscalationDialogProps { open: boolean; onOpenChange: (open: boolean) => void; onEscalate: (reason: string) => Promise; submissionType: string; + error?: { message: string; errorId?: string } | null; } const escalationReasons = [ @@ -40,6 +42,7 @@ export function EscalationDialog({ onOpenChange, onEscalate, submissionType, + error, }: EscalationDialogProps) { const [selectedReason, setSelectedReason] = useState(''); const [additionalNotes, setAdditionalNotes] = useState(''); @@ -76,6 +79,23 @@ export function EscalationDialog({ + {error && ( + + + Escalation Failed + +
+

{error.message}

+ {error.errorId && ( +

+ Reference: {error.errorId.slice(0, 8)} +

+ )} +
+
+
+ )} +
diff --git a/src/components/moderation/SubmissionReviewManager.tsx b/src/components/moderation/SubmissionReviewManager.tsx index b14a2a04..7c77bcc6 100644 --- a/src/components/moderation/SubmissionReviewManager.tsx +++ b/src/components/moderation/SubmissionReviewManager.tsx @@ -12,12 +12,12 @@ import { detectDependencyConflicts, approveSubmissionItems, rejectSubmissionItems, - escalateSubmission, checkSubmissionConflict, type SubmissionItemWithDeps, type DependencyConflict, type ConflictCheckResult } from '@/lib/submissionItemsService'; +import { useModerationActions } from '@/hooks/moderation/useModerationActions'; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription } from '@/components/ui/sheet'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; @@ -77,6 +77,10 @@ export function SubmissionReviewManager({ const [conflictData, setConflictData] = useState(null); const [showConflictResolutionModal, setShowConflictResolutionModal] = useState(false); const [lastModifiedTimestamp, setLastModifiedTimestamp] = useState(null); + const [escalationError, setEscalationError] = useState<{ + message: string; + errorId?: string; + } | null>(null); const { toast } = useToast(); const { isAdmin, isSuperuser } = useUserRole(); @@ -87,6 +91,17 @@ export function SubmissionReviewManager({ // Lock monitoring integration const { extendLock } = useLockMonitor(state, dispatch, submissionId); + // Moderation actions + const { escalateSubmission } = useModerationActions({ + user, + onActionStart: (itemId: string) => { + logger.log(`Starting escalation for ${itemId}`); + }, + onActionComplete: () => { + logger.log('Escalation complete'); + } + }); + // Auto-claim on mount useEffect(() => { if (open && submissionId && state.status === 'idle') { @@ -425,50 +440,35 @@ export function SubmissionReviewManager({ } try { - const { supabase } = await import('@/integrations/supabase/client'); - - // Call the escalation notification edge function - const { data, error, requestId } = await invokeWithTracking( - 'send-escalation-notification', - { - submissionId, - escalationReason: reason, - escalatedBy: user.id - }, - user.id - ); - - if (error) { - handleError(error, { - action: 'Send escalation notification', - userId: user.id, - metadata: { submissionId } - }); - // Fallback to direct database update if email fails - await escalateSubmission(submissionId, reason, user.id); - toast({ - title: 'Escalated (Email Failed)', - description: 'Submission escalated but notification email failed to send', - variant: 'default', - }); - } else { - toast({ - title: 'Escalated Successfully', - description: 'Submission escalated and admin notified via email', - }); - } + setEscalationError(null); + // Use consolidated action from useModerationActions + // This handles: edge function call, fallback, error logging, cache invalidation + await escalateSubmission( + { + id: submissionId, + submission_type: submissionType, + type: 'submission' + } as any, + reason + ); + + // Success - close dialog onComplete(); onOpenChange(false); - } catch (error: unknown) { - handleError(error, { - action: 'Escalate Submission', - userId: user?.id, - metadata: { - submissionId, - reason: reason.substring(0, 100) - } + } catch (error: any) { + // Track error for retry UI + setEscalationError({ + message: getErrorMessage(error), + errorId: error.errorId }); + + logger.error('Escalation failed in SubmissionReviewManager', { + submissionId, + error: getErrorMessage(error) + }); + + // Don't close dialog on error - let user retry } }; @@ -587,6 +587,7 @@ export function SubmissionReviewManager({ onOpenChange={setShowEscalationDialog} onEscalate={handleEscalate} submissionType={submissionType} + error={escalationError} /> { return Math.max(0, currentLock.expiresAt.getTime() - Date.now()); }, [currentLock]); - // Escalate submission + /** + * @deprecated Use escalateSubmission from useModerationActions instead + * This method only updates the database and doesn't send email notifications + */ const escalateSubmission = useCallback(async (submissionId: string, reason: string): Promise => { if (!user?.id) return false;