29 lines
1.6 KiB
TypeScript
29 lines
1.6 KiB
TypeScript
import { useCallback, useEffect, useState } from "react";
|
|
import { type ToastItem } from "@nodedc/ui-react";
|
|
import { APIError, loginFromLaunch, request, type Status } from "./api";
|
|
|
|
export function useNode() {
|
|
const [value, setValue] = useState<Status | null>(null);
|
|
const [pending, setPending] = useState(true);
|
|
const [locked, setLocked] = useState(false);
|
|
const [toasts, setToasts] = useState<ToastItem[]>([]);
|
|
const failure = useCallback((error: unknown) => {
|
|
if (error instanceof APIError && error.status === 401) { setValue(null); setLocked(true); }
|
|
setToasts([{ id: "request", tone: "error", title: error instanceof Error ? error.message : "Нода недоступна", durationMs: null }]);
|
|
}, []);
|
|
const refresh = useCallback(async () => {
|
|
setPending(true);
|
|
try { const result = await request<Status>("/api/status"); setValue(result); setLocked(false); setToasts([]); }
|
|
catch (error) { failure(error); }
|
|
finally { setPending(false); }
|
|
}, [failure]);
|
|
useEffect(() => {
|
|
const launch = () => { void loginFromLaunch().then(refresh).then(()=>window.dispatchEvent(new Event("mission-core-session-ready"))).catch(error => { failure(error); setPending(false); }); };
|
|
launch(); window.addEventListener("hashchange", launch);
|
|
return () => window.removeEventListener("hashchange", launch);
|
|
}, [refresh, failure]);
|
|
const success = useCallback((title: string) => setToasts([{ id: "request", tone: "success", title }]), []);
|
|
return { value, pending, locked, refresh, failure, success, toasts,
|
|
dismiss: (id: string) => setToasts(items => items.filter(item => item.id !== id)) };
|
|
}
|