From c7e18206b12396efbae36eeb10bc6caf077a07fc Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:17:34 +0000 Subject: [PATCH] Persist transaction statuses to localStorage Add persistence for transaction statuses to localStorage in ModerationQueue and SubmissionReviewManager components. This ensures that transaction statuses (processing, timeout, cached, completed, failed) are preserved across page refreshes, providing a more robust user experience during active transactions. --- src/components/moderation/ModerationQueue.tsx | 11 +++++++++- .../moderation/SubmissionReviewManager.tsx | 22 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/components/moderation/ModerationQueue.tsx b/src/components/moderation/ModerationQueue.tsx index 2abb2e48..b5d8f156 100644 --- a/src/components/moderation/ModerationQueue.tsx +++ b/src/components/moderation/ModerationQueue.tsx @@ -9,6 +9,7 @@ import { useUserRole } from '@/hooks/useUserRole'; import { useAuth } from '@/hooks/useAuth'; import { getErrorMessage } from '@/lib/errorHandler'; import { supabase } from '@/lib/supabaseClient'; +import * as localStorage from '@/lib/localStorage'; import { PhotoModal } from './PhotoModal'; import { SubmissionReviewManager } from './SubmissionReviewManager'; import { ItemEditDialog } from './ItemEditDialog'; @@ -76,7 +77,10 @@ export const ModerationQueue = forwardRef>({}); - const [transactionStatuses, setTransactionStatuses] = useState>({}); + const [transactionStatuses, setTransactionStatuses] = useState>(() => { + // Restore from localStorage on mount + return localStorage.getJSON('moderation-queue-transaction-statuses', {}); + }); const [photoModalOpen, setPhotoModalOpen] = useState(false); const [selectedPhotos, setSelectedPhotos] = useState([]); const [selectedPhotoIndex, setSelectedPhotoIndex] = useState(0); @@ -111,6 +115,11 @@ export const ModerationQueue = forwardRef { + localStorage.setJSON('moderation-queue-transaction-statuses', transactionStatuses); + }, [transactionStatuses]); + // Offline detection effect useEffect(() => { const handleOnline = () => { diff --git a/src/components/moderation/SubmissionReviewManager.tsx b/src/components/moderation/SubmissionReviewManager.tsx index 2ca96eee..fe0ebfb5 100644 --- a/src/components/moderation/SubmissionReviewManager.tsx +++ b/src/components/moderation/SubmissionReviewManager.tsx @@ -7,6 +7,7 @@ import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { moderationReducer, canApprove, canReject, hasActiveLock } from '@/lib/moderationStateMachine'; import { useLockMonitor } from '@/lib/moderation/lockMonitor'; import { useTransactionResilience } from '@/hooks/useTransactionResilience'; +import * as localStorage from '@/lib/localStorage'; import { fetchSubmissionItems, buildDependencyTree, @@ -84,8 +85,17 @@ export function SubmissionReviewManager({ message: string; errorId?: string; } | null>(null); - const [transactionStatus, setTransactionStatus] = useState<'idle' | 'processing' | 'timeout' | 'cached' | 'completed' | 'failed'>('idle'); - const [transactionMessage, setTransactionMessage] = useState(); + const [transactionStatus, setTransactionStatus] = useState<'idle' | 'processing' | 'timeout' | 'cached' | 'completed' | 'failed'>(() => { + // Restore from localStorage on mount + const stored = localStorage.getJSON<{ status: string; message?: string }>(`moderation-transaction-status-${submissionId}`, { status: 'idle' }); + const validStatuses = ['idle', 'processing', 'timeout', 'cached', 'completed', 'failed']; + return validStatuses.includes(stored.status) ? stored.status as 'idle' | 'processing' | 'timeout' | 'cached' | 'completed' | 'failed' : 'idle'; + }); + const [transactionMessage, setTransactionMessage] = useState(() => { + // Restore from localStorage on mount + const stored = localStorage.getJSON<{ status: string; message?: string }>(`moderation-transaction-status-${submissionId}`, { status: 'idle' }); + return stored.message; + }); const { toast } = useToast(); const { isAdmin, isSuperuser } = useUserRole(); @@ -116,6 +126,14 @@ export function SubmissionReviewManager({ } }); + // Persist transaction status to localStorage + useEffect(() => { + localStorage.setJSON(`moderation-transaction-status-${submissionId}`, { + status: transactionStatus, + message: transactionMessage, + }); + }, [transactionStatus, transactionMessage, submissionId]); + // Auto-claim on mount useEffect(() => { if (open && submissionId && state.status === 'idle') {