/** * React hook for fetching and updating the blocklist import schedule. */ import { useCallback, useEffect, useRef, useState } from "react"; import { fetchSchedule, updateSchedule } from "../api/blocklist"; import { handleFetchError, createStringErrorAdapter } from "../utils/fetchError"; import type { ScheduleConfig, ScheduleInfo } from "../types/blocklist"; export interface UseScheduleReturn { info: ScheduleInfo | null; loading: boolean; error: string | null; saveSchedule: (config: ScheduleConfig) => Promise; refresh: () => void; } /** * Fetch and update the blocklist import schedule. */ export function useSchedule(): UseScheduleReturn { const [info, setInfo] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const abortRef = useRef(null); const refresh = useCallback((): void => { abortRef.current?.abort(); const controller = new AbortController(); abortRef.current = controller; setLoading(true); setError(null); fetchSchedule(controller.signal) .then((data) => { if (controller.signal.aborted) return; setInfo(data); }) .catch((err: unknown) => { if (controller.signal.aborted) return; handleFetchError(err, createStringErrorAdapter(setError), "Failed to load schedule"); }) .finally(() => { if (!controller.signal.aborted) { setLoading(false); } }); }, []); useEffect(() => { refresh(); return (): void => { abortRef.current?.abort(); }; }, [refresh]); const saveSchedule = useCallback(async (config: ScheduleConfig): Promise => { const updated = await updateSchedule(config); setInfo(updated); }, []); return { info, loading, error, saveSchedule, refresh }; }