import { useRouter } from "@tanstack/react-router"; import { useState } from "react"; type ActionState = { status: "idle" } | { status: "pending" } | { status: "error"; message: string }; function messageOf(error: unknown): string { if (error instanceof Error && error.message) return error.message; return "Something went wrong"; } /** * Runs a server-function mutation, tracks its pending/error state and refreshes route loaders on success. */ export function useAction( action: (input: TInput) => Promise, options: { invalidate?: boolean } = {}, ) { const router = useRouter(); const [state, setState] = useState({ status: "idle" }); const invalidate = options.invalidate ?? true; async function run(input: TInput): Promise { setState({ status: "pending" }); try { const result = await action(input); if (invalidate) await router.invalidate(); setState({ status: "idle" }); return result; } catch (error) { setState({ status: "error", message: messageOf(error) }); return undefined; } } return { run, pending: state.status === "pending", error: state.status === "error" ? state.message : null, reset: () => setState({ status: "idle" }), }; }