85 lines
2.5 KiB
TypeScript
85 lines
2.5 KiB
TypeScript
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
import useExamEditorStore from "@/stores/examEditor";
|
|
import { Module } from "@/interfaces";
|
|
import { debounce } from "lodash";
|
|
import { SectionSettings } from "@/stores/examEditor/types";
|
|
|
|
|
|
// Since all the other components have a local state
|
|
// that then gets updated all at once, if the keydowns
|
|
// aren't here aren't throttled things can get messy
|
|
const useSettingsState = <T extends SectionSettings>(
|
|
module: Module,
|
|
sectionId: number,
|
|
) => {
|
|
const globalSettings = useExamEditorStore((state) => {
|
|
const settings = state.modules[module].sections.find(
|
|
(section) => section.sectionId === sectionId
|
|
)?.settings;
|
|
return settings as T;
|
|
});
|
|
|
|
const dispatch = useExamEditorStore((state) => state.dispatch);
|
|
|
|
const [localSettings, setLocalSettings] = useState<T>(() =>
|
|
globalSettings || {} as T
|
|
);
|
|
|
|
const pendingUpdatesRef = useRef<Partial<T>>({});
|
|
|
|
useEffect(() => {
|
|
if (globalSettings) {
|
|
setLocalSettings(globalSettings);
|
|
}
|
|
}, [globalSettings]);
|
|
|
|
const debouncedUpdateGlobal = useMemo(() => {
|
|
const debouncedFn = debounce(() => {
|
|
if (Object.keys(pendingUpdatesRef.current).length > 0) {
|
|
dispatch({
|
|
type: 'UPDATE_SECTION_SETTINGS',
|
|
payload: { sectionId, update: pendingUpdatesRef.current, module}
|
|
});
|
|
pendingUpdatesRef.current = {};
|
|
}
|
|
}, 1000);
|
|
|
|
return debouncedFn;
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [dispatch, sectionId]);
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
if (Object.keys(pendingUpdatesRef.current).length > 0) {
|
|
dispatch({
|
|
type: 'UPDATE_SECTION_SETTINGS',
|
|
payload: {sectionId, update: pendingUpdatesRef.current, module}
|
|
});
|
|
}
|
|
};
|
|
}, [dispatch, module, sectionId]);
|
|
|
|
|
|
const updateLocalAndScheduleGlobal = useCallback((updates: Partial<T>, schedule: boolean = true) => {
|
|
setLocalSettings(prev => ({
|
|
...prev,
|
|
...updates
|
|
}));
|
|
|
|
pendingUpdatesRef.current = {
|
|
...pendingUpdatesRef.current,
|
|
...updates
|
|
};
|
|
if (schedule) {
|
|
debouncedUpdateGlobal();
|
|
}
|
|
}, [debouncedUpdateGlobal]);
|
|
|
|
return {
|
|
localSettings,
|
|
updateLocalAndScheduleGlobal
|
|
};
|
|
};
|
|
|
|
export default useSettingsState;
|