ge-tool/utils/use-realtime-submissions.ts
2025-12-10 13:41:43 +07:00

103 lines
2.7 KiB
TypeScript
Executable File

/**
* Hook for Supabase Realtime Submissions
* Subscribes to submissions table changes and updates UI in realtime
*/
import { useEffect, useCallback, useRef } from 'react';
import { RealtimeChannel } from '@supabase/supabase-js';
import { supabase } from './supabase';
export interface SubmissionRecord {
id: string;
submission_id: string;
status: 'pending' | 'processing' | 'completed' | 'failed';
input: any;
results: any[] | null;
error_message: string | null;
created_at: string;
updated_at: string;
submission_type: 'tms_permission' | 'raw_download';
}
interface UseRealtimeSubmissionsOptions {
onInsert?: (record: SubmissionRecord) => void;
onUpdate?: (record: SubmissionRecord) => void;
onDelete?: (record: SubmissionRecord) => void;
/** Optional: filter by submission_type */
submissionType?: 'tms_permission' | 'raw_download';
}
/**
* Subscribe to realtime changes on submissions table
*/
export function useRealtimeSubmissions(options: UseRealtimeSubmissionsOptions = {}) {
const { onInsert, onUpdate, onDelete, submissionType } = options;
const channelRef = useRef<RealtimeChannel | null>(null);
const subscribe = useCallback(() => {
// Unsubscribe existing channel
if (channelRef.current) {
channelRef.current.unsubscribe();
}
// Create filter if submissionType provided
const filter = submissionType ? `submission_type=eq.${submissionType}` : undefined;
const channel = supabase
.channel('submissions-changes')
.on(
'postgres_changes',
{
event: 'INSERT',
schema: 'public',
table: 'submissions',
filter,
},
(payload) => {
onInsert?.(payload.new as SubmissionRecord);
}
)
.on(
'postgres_changes',
{
event: 'UPDATE',
schema: 'public',
table: 'submissions',
filter,
},
(payload) => {
onUpdate?.(payload.new as SubmissionRecord);
}
)
.on(
'postgres_changes',
{
event: 'DELETE',
schema: 'public',
table: 'submissions',
filter,
},
(payload) => {
onDelete?.(payload.old as SubmissionRecord);
}
)
.subscribe();
channelRef.current = channel;
return () => {
channel.unsubscribe();
};
}, [onInsert, onUpdate, onDelete, submissionType]);
useEffect(() => {
const cleanup = subscribe();
return cleanup;
}, [subscribe]);
return {
/** Manually resubscribe */
resubscribe: subscribe,
};
}