Files
zeekayandHanzo Dev f5af7d38b9 fix(react): type refs and JSX the way React 19's types do
@types/react went from 18 to 19 with React. Three of its changes reached
this code, none of them at run time:

- useRef(null) is a RefObject<T | null>, so the PDF viewer's constraint ref
  and the signature pad's validity check take one. The virtual list the
  first is handed to already did, and the check already returns false when
  current is null.
- useRef takes its initial value; the autosave timer and the signing card's
  timeout pass undefined, which is what useRef() gave them.
- The global JSX namespace is gone; the role icons import JSX from react.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-19 04:35:04 -07:00

65 lines
1.6 KiB
TypeScript

import { useCallback, useEffect, useRef } from 'react';
type SaveRequest<T, R> = {
data: T;
onResponse?: (response: R) => void;
};
export const useAutoSave = <T, R = void>(
onSave: (data: T) => Promise<R>,
options: { delay?: number } = {},
) => {
const { delay = 2000 } = options;
const saveTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
const saveQueueRef = useRef<SaveRequest<T, R>[]>([]);
const isProcessingRef = useRef(false);
const processQueue = async () => {
if (isProcessingRef.current || saveQueueRef.current.length === 0) {
return;
}
isProcessingRef.current = true;
while (saveQueueRef.current.length > 0) {
const request = saveQueueRef.current.shift()!;
try {
const response = await onSave(request.data);
request.onResponse?.(response);
} catch (error) {
console.error('Auto-save failed:', error);
}
}
isProcessingRef.current = false;
};
const saveFormData = async (data: T, onResponse?: (response: R) => void) => {
saveQueueRef.current.push({ data, onResponse });
await processQueue();
};
const scheduleSave = useCallback(
(data: T, onResponse?: (response: R) => void) => {
if (saveTimeoutRef.current) {
clearTimeout(saveTimeoutRef.current);
}
saveTimeoutRef.current = setTimeout(() => void saveFormData(data, onResponse), delay);
},
[delay],
);
useEffect(() => {
return () => {
if (saveTimeoutRef.current) {
clearTimeout(saveTimeoutRef.current);
}
};
}, []);
return { scheduleSave };
};