Files
Gitead-DentalManagementMHnewff/apps/Frontend/src/hooks/use-job-status.ts
ff 90302a76b7 feat: add BullMQ queue infrastructure and frontend job status hook
- apps/Backend/src/queue/: connection, queues, workers, processors
- apps/Frontend/src/hooks/use-job-status.ts: WebSocket job progress hook
- apps/Frontend/src/lib/socket.ts: shared Socket.IO singleton

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 22:30:40 -04:00

79 lines
2.2 KiB
TypeScript

/**
* useJobStatus — tracks a BullMQ job via WebSocket `job:update` events.
*
* Usage:
* const { status, result, error } = useJobStatus(jobId);
*
* The hook listens for `job:update` events emitted by the backend workers.
* When the jobId changes, the previous listener is removed and a fresh one
* is registered for the new job.
*/
import { useEffect, useState } from "react";
import { socket } from "@/lib/socket";
export type JobStatus = "queued" | "active" | "completed" | "failed" | null;
export interface JobUpdatePayload {
jobId: string;
jobType: string;
status: JobStatus;
message?: string;
result?: any;
error?: string;
}
export interface UseJobStatusReturn {
status: JobStatus;
message: string;
result: any;
error: string | null;
socketId: string | null;
}
export function useJobStatus(jobId: string | null): UseJobStatusReturn {
const [status, setStatus] = useState<JobStatus>(jobId ? "queued" : null);
const [message, setMessage] = useState("");
const [result, setResult] = useState<any>(null);
const [error, setError] = useState<string | null>(null);
const [socketId, setSocketId] = useState<string | null>(
socket.id ?? null
);
// Keep socketId in sync with the socket connection
useEffect(() => {
const onConnect = () => setSocketId(socket.id ?? null);
socket.on("connect", onConnect);
if (socket.connected) setSocketId(socket.id ?? null);
return () => { socket.off("connect", onConnect); };
}, []);
// Reset state when the jobId changes
useEffect(() => {
if (!jobId) {
setStatus(null);
setMessage("");
setResult(null);
setError(null);
return;
}
setStatus("queued");
setMessage("");
setResult(null);
setError(null);
const handler = (payload: JobUpdatePayload) => {
if (payload.jobId !== jobId) return;
setStatus(payload.status);
if (payload.message) setMessage(payload.message);
if (payload.result !== undefined) setResult(payload.result);
if (payload.error) setError(payload.error);
};
socket.on("job:update", handler);
return () => { socket.off("job:update", handler); };
}, [jobId]);
return { status, message, result, error, socketId };
}