All files / packages/app/hooks use-autosave.tsx

90.9% Statements 20/22
88.88% Branches 8/9
87.5% Functions 7/8
94.73% Lines 18/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71                    15829x             17301x 17301x 17301x 8x 8x   17301x 17301x     17301x   17301x                         17301x                       88x           18663x 17301x 17301x 1209x     13x 13x      
import React from "react";
 
import type { AnyFormApi } from "@tanstack/react-form";
import { useStore } from "@tanstack/react-form";
import { useDebouncedCallback } from "@tanstack/react-pacer";
 
import { Icon } from "~components/icons";
import { Spinner } from "~components/spinner";
import { cn } from "~components/utils";
 
export const useAutosave = ({
	isUpdatePending,
	submitDebounceMs = 2000,
}: {
	isUpdatePending: boolean;
	submitDebounceMs?: number;
}) => {
	const [eagerToSubmit, setEagerToSubmit] = React.useState(false);
	const [justSaved, setJustSaved] = React.useState(false);
	const onSuccess = React.useCallback(() => {
		setJustSaved(true);
		setTimeout(() => setJustSaved(false), 2000);
	}, []);
	const onSubmitImmediate = React.useCallback(() => setEagerToSubmit(true), []);
	const onSubmit = useDebouncedCallback(onSubmitImmediate, {
		wait: submitDebounceMs,
	});
	const updateElement = React.useMemo(
		() =>
			isUpdatePending ? (
				<Spinner size="xs" />
			) : (
				<Icon
					name="check"
					className={cn(
						"text-success size-3 transition-opacity duration-500",
						justSaved ? "opacity-100" : "opacity-0",
					)}
				/>
			),
		[isUpdatePending, justSaved],
	);
	return {
		onSuccess,
		onSubmit,
		onSubmitImmediate,
		updateElement,
		eagerToSubmitState: [eagerToSubmit, setEagerToSubmit] satisfies [
			boolean,
			React.Dispatch<React.SetStateAction<boolean>>,
		],
	};
};
 
export const useAutosaveEffect = (
	form: AnyFormApi,
	{
		state: eagerState,
	}: { state: [boolean, React.Dispatch<React.SetStateAction<boolean>>] },
) => {
	const isSubmitting = useStore(form.store, (state) => state.isSubmitting);
	const [eagerToSubmit, setEagerToSubmit] = eagerState;
	React.useEffect(() => {
		Iif (!eagerToSubmit || isSubmitting) {
			return;
		}
		setEagerToSubmit(false);
		void form.handleSubmit();
	}, [eagerToSubmit, form, isSubmitting, setEagerToSubmit]);
};