import type { MutationKey } from "@tanstack/react-query"; import { useMemo } from "react"; import { showToast } from "../lib/toast"; interface MutationOptions { mutationKey: MutationKey; mutationFn: (vars: TVariables) => Promise; onSettled?: () => void; onError?: (err: TError) => void; onSuccess?: (data: TData) => void; disableToastError?: boolean; } type CallbackMutationOptions = Omit< MutationOptions, "mutationKey" | "mutationFn" >; export function createFastMutation( defaultArgs: MutationOptions, ) { const mutateAsync = async ( variables: TVariables, args?: CallbackMutationOptions, ) => { const { mutationKey, mutationFn, disableToastError } = { ...defaultArgs, ...args, }; try { const data = await mutationFn(variables); // Run both default and custom onSuccess callbacks defaultArgs.onSuccess?.(data); args?.onSuccess?.(data); defaultArgs.onSettled?.(); args?.onSettled?.(); return data; } catch (err: unknown) { const stringKey = mutationKey.join("."); const e = err as TError; console.log("mutation error", stringKey, e); if (!disableToastError) { showToast({ id: stringKey, message: err instanceof Error ? err.message : String(err), color: "danger", timeout: 5000, }); } // Run both default and custom onError callbacks defaultArgs.onError?.(e); args?.onError?.(e); defaultArgs.onSettled?.(); args?.onSettled?.(); throw e; } }; const mutate = ( variables: TVariables, args?: CallbackMutationOptions, ) => { setTimeout(() => mutateAsync(variables, args)); }; return { mutateAsync, mutate }; } export function useFastMutation( defaultArgs: MutationOptions, ) { return useMemo(() => { return createFastMutation(defaultArgs); // oxlint-disable-next-line react-hooks/exhaustive-deps -- Force it! }, defaultArgs.mutationKey); }