123 lines
3.3 KiB
TypeScript
123 lines
3.3 KiB
TypeScript
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<string, JobStream>;
|
||
};
|
||
|
||
const LiveContext = createContext<LiveContextValue | undefined>(undefined);
|
||
|
||
export const LiveProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||
const socket = useSocket();
|
||
const [state, setState] = useState<LiveState>({ value: 0, running: false });
|
||
const [jobStreams, setJobStreams] = useState<Record<string, JobStream>>({});
|
||
|
||
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 <LiveContext.Provider value={value}>{children}</LiveContext.Provider>;
|
||
};
|
||
|
||
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]);
|
||
}
|