mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 07:51:13 -05:00
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.
This commit is contained in:
@@ -9,6 +9,7 @@ import { useUserRole } from '@/hooks/useUserRole';
|
|||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { getErrorMessage } from '@/lib/errorHandler';
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { supabase } from '@/lib/supabaseClient';
|
import { supabase } from '@/lib/supabaseClient';
|
||||||
|
import * as localStorage from '@/lib/localStorage';
|
||||||
import { PhotoModal } from './PhotoModal';
|
import { PhotoModal } from './PhotoModal';
|
||||||
import { SubmissionReviewManager } from './SubmissionReviewManager';
|
import { SubmissionReviewManager } from './SubmissionReviewManager';
|
||||||
import { ItemEditDialog } from './ItemEditDialog';
|
import { ItemEditDialog } from './ItemEditDialog';
|
||||||
@@ -76,7 +77,10 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
|
|||||||
|
|
||||||
// UI-only state
|
// UI-only state
|
||||||
const [notes, setNotes] = useState<Record<string, string>>({});
|
const [notes, setNotes] = useState<Record<string, string>>({});
|
||||||
const [transactionStatuses, setTransactionStatuses] = useState<Record<string, { status: 'idle' | 'processing' | 'timeout' | 'cached' | 'completed' | 'failed'; message?: string }>>({});
|
const [transactionStatuses, setTransactionStatuses] = useState<Record<string, { status: 'idle' | 'processing' | 'timeout' | 'cached' | 'completed' | 'failed'; message?: string }>>(() => {
|
||||||
|
// Restore from localStorage on mount
|
||||||
|
return localStorage.getJSON('moderation-queue-transaction-statuses', {});
|
||||||
|
});
|
||||||
const [photoModalOpen, setPhotoModalOpen] = useState(false);
|
const [photoModalOpen, setPhotoModalOpen] = useState(false);
|
||||||
const [selectedPhotos, setSelectedPhotos] = useState<PhotoItem[]>([]);
|
const [selectedPhotos, setSelectedPhotos] = useState<PhotoItem[]>([]);
|
||||||
const [selectedPhotoIndex, setSelectedPhotoIndex] = useState(0);
|
const [selectedPhotoIndex, setSelectedPhotoIndex] = useState(0);
|
||||||
@@ -111,6 +115,11 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
|
|||||||
// Offline detection state
|
// Offline detection state
|
||||||
const [isOffline, setIsOffline] = useState(!navigator.onLine);
|
const [isOffline, setIsOffline] = useState(!navigator.onLine);
|
||||||
|
|
||||||
|
// Persist transaction statuses to localStorage
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setJSON('moderation-queue-transaction-statuses', transactionStatuses);
|
||||||
|
}, [transactionStatuses]);
|
||||||
|
|
||||||
// Offline detection effect
|
// Offline detection effect
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleOnline = () => {
|
const handleOnline = () => {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
|
|||||||
import { moderationReducer, canApprove, canReject, hasActiveLock } from '@/lib/moderationStateMachine';
|
import { moderationReducer, canApprove, canReject, hasActiveLock } from '@/lib/moderationStateMachine';
|
||||||
import { useLockMonitor } from '@/lib/moderation/lockMonitor';
|
import { useLockMonitor } from '@/lib/moderation/lockMonitor';
|
||||||
import { useTransactionResilience } from '@/hooks/useTransactionResilience';
|
import { useTransactionResilience } from '@/hooks/useTransactionResilience';
|
||||||
|
import * as localStorage from '@/lib/localStorage';
|
||||||
import {
|
import {
|
||||||
fetchSubmissionItems,
|
fetchSubmissionItems,
|
||||||
buildDependencyTree,
|
buildDependencyTree,
|
||||||
@@ -84,8 +85,17 @@ export function SubmissionReviewManager({
|
|||||||
message: string;
|
message: string;
|
||||||
errorId?: string;
|
errorId?: string;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
const [transactionStatus, setTransactionStatus] = useState<'idle' | 'processing' | 'timeout' | 'cached' | 'completed' | 'failed'>('idle');
|
const [transactionStatus, setTransactionStatus] = useState<'idle' | 'processing' | 'timeout' | 'cached' | 'completed' | 'failed'>(() => {
|
||||||
const [transactionMessage, setTransactionMessage] = useState<string | undefined>();
|
// 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<string | undefined>(() => {
|
||||||
|
// 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 { toast } = useToast();
|
||||||
const { isAdmin, isSuperuser } = useUserRole();
|
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
|
// Auto-claim on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open && submissionId && state.status === 'idle') {
|
if (open && submissionId && state.status === 'idle') {
|
||||||
|
|||||||
Reference in New Issue
Block a user