import React, { createContext, useContext, useEffect, useMemo, useState } from "react"; import { useSocket } from "./socket-provider"; type LiveState = { value: number; running: boolean; }; type JobStream = { logs: string[]; status?: string; lastRunAt?: string; lastMessage?: string; }; type LiveContextValue = LiveState & { startCounter: () => void; stopCounter: () => void; jobStreams: Record; }; const LiveContext = createContext(undefined); export const LiveProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const socket = useSocket(); const [state, setState] = useState({ value: 0, running: false }); const [jobStreams, setJobStreams] = useState>({}); useEffect(() => { if (!socket) return; const handleUpdate = (payload: { value: number }) => { setState({ value: payload.value, running: true }); }; const handleStopped = (payload: { value: number }) => { setState({ value: payload.value, running: false }); }; socket.on("counter:update", handleUpdate); socket.on("counter:stopped", handleStopped); const handleJobLog = ({ jobId, line }: { jobId: string; line: string }) => { if (!jobId) return; setJobStreams((prev) => { const current = prev[jobId] || { logs: [] }; const nextLogs = [...current.logs, line].slice(-200); return { ...prev, [jobId]: { ...current, logs: nextLogs } }; }); }; const handleJobStatus = ({ jobId, status, lastRunAt, lastMessage }: { jobId: string; status?: string; lastRunAt?: string; lastMessage?: string; }) => { if (!jobId) return; setJobStreams((prev) => { const current = prev[jobId] || { logs: [] }; return { ...prev, [jobId]: { ...current, status, lastRunAt, lastMessage } }; }); }; socket.emit("counter:status", (payload: { value: number; running: boolean }) => { setState({ value: payload.value, running: payload.running }); }); socket.on("job:log", handleJobLog); socket.on("job:status", handleJobStatus); return () => { socket.off("counter:update", handleUpdate); socket.off("counter:stopped", handleStopped); socket.off("job:log", handleJobLog); socket.off("job:status", handleJobStatus); }; }, [socket]); const startCounter = useMemo( () => () => { socket?.emit("counter:start"); }, [socket] ); const stopCounter = useMemo( () => () => { socket?.emit("counter:stop"); }, [socket] ); const value = useMemo( () => ({ value: state.value, running: state.running, startCounter, stopCounter, jobStreams }), [state, startCounter, stopCounter, jobStreams] ); return {children}; }; export function useLiveCounter() { const ctx = useContext(LiveContext); if (!ctx) throw new Error("useLiveCounter LiveProvider içinde kullanılmalı"); return ctx; } export function useJobStream(jobId: string) { const ctx = useContext(LiveContext); if (!ctx) throw new Error("useJobStream LiveProvider içinde kullanılmalı"); return useMemo(() => ctx.jobStreams[jobId] || { logs: [], status: "idle" }, [ctx.jobStreams, jobId]); }