93 lines
2.7 KiB
TypeScript
93 lines
2.7 KiB
TypeScript
"use client";
|
|
import { useCallback, useRef, useState } from "react";
|
|
import { toast } from "sonner";
|
|
import { useVisiblePolling } from "@/hooks/use-visible-polling";
|
|
import { adminFetch } from "@/lib/admin-fetch";
|
|
import type { ImportJob, ImportJobItem } from "@/lib/furni/import-job";
|
|
export function useFurnitureJobs(onComplete: () => void) {
|
|
const [jobs, setJobs] = useState<ImportJob[]>([]),
|
|
[busy, setBusy] = useState(false),
|
|
[error, setError] = useState("");
|
|
const completed = useRef(new Set<string>()),
|
|
callback = useRef(onComplete);
|
|
callback.current = onComplete;
|
|
const request = useRef<{ payload: string; id: string } | null>(null);
|
|
const submitting = useRef(false);
|
|
const refreshing = useRef(false);
|
|
const refresh = useCallback(async () => {
|
|
if (refreshing.current) return;
|
|
refreshing.current = true;
|
|
try {
|
|
const response = await adminFetch("/api/admin/studio/import-jobs");
|
|
const data = await response.json();
|
|
if (!response.ok)
|
|
throw Error(
|
|
data.error || `Import history unavailable (${response.status})`,
|
|
);
|
|
setJobs(data.jobs);
|
|
setError("");
|
|
let changed = false;
|
|
for (const job of data.jobs as ImportJob[])
|
|
if (
|
|
(job.state === "completed" || job.state === "interrupted") &&
|
|
!completed.current.has(job.id)
|
|
) {
|
|
completed.current.add(job.id);
|
|
changed = true;
|
|
}
|
|
if (changed) callback.current();
|
|
} catch (error) {
|
|
setError(
|
|
error instanceof Error ? error.message : "Cannot load import history",
|
|
);
|
|
} finally {
|
|
refreshing.current = false;
|
|
}
|
|
}, []);
|
|
useVisiblePolling(refresh, 5000);
|
|
const submit = async (
|
|
items: ImportJobItem[],
|
|
options: {
|
|
sourceId?: string;
|
|
translate: boolean;
|
|
langs?: string[];
|
|
mode?: "repair";
|
|
},
|
|
) => {
|
|
if (submitting.current) return false;
|
|
submitting.current = true;
|
|
setBusy(true);
|
|
const body = { items, ...options },
|
|
payload = JSON.stringify(body);
|
|
if (request.current?.payload !== payload)
|
|
request.current = { payload, id: crypto.randomUUID() };
|
|
try {
|
|
const response = await adminFetch("/api/admin/studio/import-jobs", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ ...body, id: request.current.id }),
|
|
});
|
|
const data = await response.json();
|
|
if (!response.ok)
|
|
throw Error(
|
|
data.error || `Could not queue import (${response.status})`,
|
|
);
|
|
request.current = null;
|
|
await refresh();
|
|
toast.success(
|
|
"Import queued. You can leave this page and return to its history.",
|
|
);
|
|
return true;
|
|
} catch (error) {
|
|
toast.error(
|
|
error instanceof Error ? error.message : "Could not queue import",
|
|
);
|
|
return false;
|
|
} finally {
|
|
submitting.current = false;
|
|
setBusy(false);
|
|
}
|
|
};
|
|
return { jobs, busy, error, submit, refresh };
|
|
}
|