import { useCallback, useState } from "react"; import { TaskInfos } from "src/components/Tasks/TaskTypes"; import { get, post } from "src/lib/api"; import { TaskApiHook } from "src/types/Hooks"; import { BaseTask, ServerTaskResponse, TaskResponse, TaskType as TaskTypeEnum } from "src/types/Task"; import { AllTaskReplies } from "src/types/TaskResponses"; import useSWRImmutable from "swr/immutable"; import useSWRMutation from "swr/mutation"; export const useGenericTaskAPI = ( taskType: TaskTypeEnum ): TaskApiHook => { const [response, setResponse] = useState>({ taskAvailability: "AWAITING_INITIAL" }); // Note: We use isValidating to indicate we are loading because it signals eash load, not just the first one. const { isValidating: isLoading, mutate: requestNewTask } = useSWRImmutable>( "/api/new_task/" + taskType, get, { onSuccess: (taskResponse) => { setResponse({ ...taskResponse, taskAvailability: "AVAILABLE", taskInfo: TaskInfos.find((taskType) => taskType.type === taskResponse.task.type), }); }, onError: () => { // We could check for code 503 here for truly unavailable, but we need to do something with other errors anyway. setResponse({ taskAvailability: "NONE_AVAILABLE" }); }, revalidateOnMount: true, dedupingInterval: 500, } ); const { trigger: sendTaskContent } = useSWRMutation("/api/update_task", post, { onSuccess: () => { requestNewTask(); }, onError: () => { // We could check for code 503 here for truly unavailable, but we need to do something with other errors anyway. setResponse({ taskAvailability: "NONE_AVAILABLE" }); }, }); // NOTE: it might make sense to split this hook into 2 parts // makes sure that requestNewTask is always called without parameters: const skipTask = useCallback(async () => { await requestNewTask(); }, [requestNewTask]); const { trigger: sendRejection } = useSWRMutation("/api/reject_task", post, { onSuccess: skipTask }); const rejectTask = useCallback( async (reason: string) => { if (response.taskAvailability !== "AVAILABLE") { throw new Error("Cannot reject task that is not yet ready"); } await sendRejection({ id: response.id, reason }); }, [response, sendRejection] ); const completeTask = useCallback( async (content: ResponseContent) => { if (response.taskAvailability !== "AVAILABLE") { throw new Error("Cannot complete task that is not yet ready"); } await sendTaskContent({ id: response.id, update_type: response.taskInfo.update_type, content }); }, [response, sendTaskContent] ); return { response, isLoading, rejectTask, completeTask }; };