Exam generation rework, batch user tables, fastapi endpoint switch
This commit is contained in:
67
src/components/ExamEditor/Hooks/useSectionEdit.tsx
Normal file
67
src/components/ExamEditor/Hooks/useSectionEdit.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import useExamEditorStore from '@/stores/examEditor';
|
||||
import ExamEditorStore from '@/stores/examEditor/types';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
interface Props {
|
||||
sectionId: number;
|
||||
mode?: "delete" | "edit";
|
||||
editing?: boolean;
|
||||
setEditing?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
onSave?: () => void;
|
||||
onDiscard?: () => void;
|
||||
onMode?: () => void;
|
||||
}
|
||||
|
||||
const useSectionEdit = ({
|
||||
sectionId,
|
||||
editing: externalEditing = false,
|
||||
setEditing: externalSetEditing,
|
||||
onSave,
|
||||
onDiscard,
|
||||
onMode
|
||||
}: Props) => {
|
||||
const { dispatch } = useExamEditorStore();
|
||||
const [internalEditing, setInternalEditing] = useState<boolean>(externalEditing);
|
||||
const editing = externalSetEditing !== undefined ? externalEditing : internalEditing;
|
||||
const setEditing = externalSetEditing !== undefined ? externalSetEditing : setInternalEditing;
|
||||
|
||||
|
||||
const updateRoot = useCallback((updates: Partial<ExamEditorStore>) => {
|
||||
dispatch({ type: 'UPDATE_ROOT', payload: { updates } });
|
||||
}, [dispatch]);
|
||||
|
||||
const handleEdit = useCallback(() => {
|
||||
setEditing(true);
|
||||
}, [sectionId, setEditing, updateRoot]);
|
||||
|
||||
const handleSave = useCallback(() => {
|
||||
if (onSave) {
|
||||
onSave();
|
||||
} else {
|
||||
setEditing(false);
|
||||
}
|
||||
|
||||
}, [setEditing, updateRoot, onSave, sectionId]);
|
||||
|
||||
const handleDiscard = useCallback(() => {
|
||||
setEditing(false);
|
||||
onDiscard?.();
|
||||
}, [setEditing, updateRoot, onDiscard, sectionId]);
|
||||
|
||||
const modeHandle = useCallback(() => {
|
||||
setEditing(!editing);
|
||||
onMode?.();
|
||||
|
||||
}, [setEditing, editing, updateRoot, onMode, sectionId]);
|
||||
|
||||
return {
|
||||
editing,
|
||||
setEditing,
|
||||
handleEdit,
|
||||
handleSave,
|
||||
handleDiscard,
|
||||
modeHandle,
|
||||
};
|
||||
};
|
||||
|
||||
export default useSectionEdit;
|
||||
81
src/components/ExamEditor/Hooks/useSettingsState.tsx
Normal file
81
src/components/ExamEditor/Hooks/useSettingsState.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
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}
|
||||
});
|
||||
pendingUpdatesRef.current = {};
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
return debouncedFn;
|
||||
}, [dispatch, sectionId]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (Object.keys(pendingUpdatesRef.current).length > 0) {
|
||||
dispatch({
|
||||
type: 'UPDATE_SECTION_SETTINGS',
|
||||
payload: {sectionId, update: pendingUpdatesRef.current}
|
||||
});
|
||||
}
|
||||
};
|
||||
}, [dispatch, module, sectionId]);
|
||||
|
||||
|
||||
const updateLocalAndScheduleGlobal = useCallback((updates: Partial<T>) => {
|
||||
setLocalSettings(prev => ({
|
||||
...prev,
|
||||
...updates
|
||||
}));
|
||||
|
||||
pendingUpdatesRef.current = {
|
||||
...pendingUpdatesRef.current,
|
||||
...updates
|
||||
};
|
||||
debouncedUpdateGlobal();
|
||||
}, [debouncedUpdateGlobal]);
|
||||
|
||||
return {
|
||||
localSettings,
|
||||
updateLocalAndScheduleGlobal
|
||||
};
|
||||
};
|
||||
|
||||
export default useSettingsState;
|
||||
Reference in New Issue
Block a user