import type { MutationKey } from '@tanstack/react-query'; import { useMemo } from 'react'; import { showToast } from '../lib/toast'; import { trackEvent } from '../lib/analytics'; 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, onSuccess, onError, onSettled, disableToastError } = { ...defaultArgs, ...args, }; try { const data = await mutationFn(variables); onSuccess?.(data); return data; } catch (err: unknown) { const stringKey = mutationKey.join('.'); const e = err as TError; console.log('mutation error', stringKey, e); trackEvent('mutation', 'error', { key: stringKey }); if (!disableToastError) { showToast({ id: stringKey, message: `${err}`, color: 'danger', timeout: 5000, }); } onError?.(e); } finally { onSettled?.(); } return null; }; const mutate = ( variables: TVariables, args?: CallbackMutationOptions, ) => { setTimeout(() => mutateAsync(variables, args)); }; return { mutateAsync, mutate }; } export function useFastMutation( defaultArgs: MutationOptions, ) { return useMemo(() => { return createFastMutation(defaultArgs); // eslint-disable-next-line react-hooks/exhaustive-deps }, defaultArgs.mutationKey); }