Try to fix languages profiles editor by introducing a new submit hooks source in the settings page #1924

pull/1979/head v1.1.3-beta.6
LASER-Yi 2 years ago
parent 70fe14562f
commit c08ba5f793

@ -10,30 +10,13 @@ import { Badge, Container, Group, LoadingOverlay } from "@mantine/core";
import { useForm } from "@mantine/form";
import { useDocumentTitle } from "@mantine/hooks";
import { FunctionComponent, ReactNode, useCallback, useMemo } from "react";
import { enabledLanguageKey, languageProfileKey } from "../keys";
import { FormContext, FormValues } from "../utilities/FormValues";
import {
SubmitHooksProvider,
useSubmitHooksSource,
} from "../utilities/HooksProvider";
import { SettingsProvider } from "../utilities/SettingsProvider";
type SubmitHookType = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: (value: any) => unknown;
};
export const submitHooks: SubmitHookType = {
[languageProfileKey]: (value) => JSON.stringify(value),
[enabledLanguageKey]: (value: Language.Info[]) => value.map((v) => v.code2),
};
function invokeHooks(settings: LooseObject) {
for (const key in settings) {
if (key in submitHooks) {
const value = settings[key];
const fn = submitHooks[key];
settings[key] = fn(value);
}
}
}
interface Props {
name: string;
children: ReactNode;
@ -45,6 +28,8 @@ const Layout: FunctionComponent<Props> = (props) => {
const { data: settings, isLoading, isRefetching } = useSystemSettings();
const { mutate, isLoading: isMutating } = useSettingsMutation();
const submitHooks = useSubmitHooksSource();
const form = useForm<FormValues>({
initialValues: {
settings: {},
@ -66,7 +51,7 @@ const Layout: FunctionComponent<Props> = (props) => {
if (Object.keys(settings).length > 0) {
const settingsToSubmit = { ...settings };
invokeHooks(settingsToSubmit);
submitHooks.invoke(settingsToSubmit);
LOG("info", "submitting settings", settingsToSubmit);
mutate(settingsToSubmit);
}
@ -77,7 +62,7 @@ const Layout: FunctionComponent<Props> = (props) => {
updateStorage(storagesToSubmit);
}
},
[mutate, updateStorage]
[mutate, submitHooks, updateStorage]
);
const totalStagedCount = useMemo(() => {
@ -100,30 +85,36 @@ const Layout: FunctionComponent<Props> = (props) => {
return (
<SettingsProvider value={settings}>
<LoadingProvider value={isLoading || isMutating}>
<form onSubmit={form.onSubmit(submit)}>
<Toolbox>
<Group>
<Toolbox.Button
type="submit"
icon={faSave}
loading={isMutating}
disabled={totalStagedCount === 0}
rightIcon={
<Badge size="xs" radius="sm" hidden={totalStagedCount === 0}>
{totalStagedCount}
</Badge>
}
>
Save
</Toolbox.Button>
</Group>
</Toolbox>
<FormContext.Provider value={form}>
<Container size="xl" mx={0}>
{children}
</Container>
</FormContext.Provider>
</form>
<SubmitHooksProvider value={submitHooks}>
<form onSubmit={form.onSubmit(submit)}>
<Toolbox>
<Group>
<Toolbox.Button
type="submit"
icon={faSave}
loading={isMutating}
disabled={totalStagedCount === 0}
rightIcon={
<Badge
size="xs"
radius="sm"
hidden={totalStagedCount === 0}
>
{totalStagedCount}
</Badge>
}
>
Save
</Toolbox.Button>
</Group>
</Toolbox>
<FormContext.Provider value={form}>
<Container size="xl" mx={0}>
{children}
</Container>
</FormContext.Provider>
</form>
</SubmitHooksProvider>
</LoadingProvider>
</SettingsProvider>
);

@ -0,0 +1,95 @@
import {
createContext,
FunctionComponent,
useCallback,
useContext,
useMemo,
useRef,
useState,
} from "react";
import { enabledLanguageKey, languageProfileKey } from "../keys";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type HookType = (value: any) => unknown;
export type SubmitHookType = {
[key: string]: HookType;
};
export type SubmitHookModifierType = {
add: (key: string, fn: HookType) => void;
remove: (key: string) => void;
invoke: (settings: LooseObject) => void;
};
const SubmitHooksContext = createContext<SubmitHookModifierType | null>(null);
type SubmitHooksProviderProps = {
value: SubmitHookModifierType;
};
export const SubmitHooksProvider: FunctionComponent<
SubmitHooksProviderProps
> = ({ value, children }) => {
return (
<SubmitHooksContext.Provider value={value}>
{children}
</SubmitHooksContext.Provider>
);
};
export function useSubmitHooks() {
const context = useContext(SubmitHooksContext);
if (context === null) {
throw new Error(
"useSubmitHooksModifier must be used within a SubmitHooksProvider"
);
}
return context;
}
export function useSubmitHooksSource(): SubmitHookModifierType {
const [submitHooks, setSubmitHooks] = useState<SubmitHookType>({
[languageProfileKey]: (value) => JSON.stringify(value),
[enabledLanguageKey]: (value: Language.Info[]) => value.map((v) => v.code2),
});
const hooksRef = useRef(submitHooks);
const invokeHooks = useCallback((settings: LooseObject) => {
const hooks = hooksRef.current;
for (const key in settings) {
if (key in hooks) {
const value = settings[key];
const fn = hooks[key];
settings[key] = fn(value);
}
}
}, []);
const addHook = useCallback(
(key: string, fn: (value: unknown) => unknown) => {
setSubmitHooks((hooks) => ({ ...hooks, [key]: fn }));
},
[]
);
const removeHook = useCallback((key: string) => {
setSubmitHooks((hooks) => {
const newHooks = { ...hooks };
delete newHooks[key];
return newHooks;
});
}, []);
return useMemo(
() => ({
add: addHook,
remove: removeHook,
invoke: invokeHooks,
}),
[addHook, invokeHooks, removeHook]
);
}

@ -1,13 +1,13 @@
import { LOG } from "@/utilities/console";
import { get, isNull, isUndefined, uniqBy } from "lodash";
import { useCallback, useEffect, useMemo, useRef } from "react";
import { submitHooks } from "../components";
import {
FormKey,
useFormActions,
useStagedValues,
} from "../utilities/FormValues";
import { useSettings } from "../utilities/SettingsProvider";
import { useSubmitHooks } from "./HooksProvider";
export interface BaseInput<T> {
disabled?: boolean;
@ -52,20 +52,22 @@ export function useSettingValue<T>(
const optionsRef = useRef(options);
const submitHooks = useSubmitHooks();
useEffect(() => {
const onSubmit = optionsRef.current?.onSubmit;
if (onSubmit) {
LOG("info", "Adding submit hook for", key);
submitHooks[key] = onSubmit;
submitHooks.add(key, onSubmit);
}
return () => {
if (key in submitHooks) {
LOG("info", "Removing submit hook for", key);
delete submitHooks[key];
submitHooks.remove(key);
}
};
}, [key]);
}, [key, submitHooks]);
const originalValue = useMemo(() => {
const onLoaded = optionsRef.current?.onLoaded;

Loading…
Cancel
Save