bazarr/frontend/src/pages/views/MassEditor.tsx

119 lines
3.3 KiB
TypeScript

import { useIsAnyMutationRunning, useLanguageProfiles } from "@/apis/hooks";
import { SimpleTable, Toolbox } from "@/components";
import { Selector, SelectorOption } from "@/components/inputs";
import { useCustomSelection } from "@/components/tables/plugins";
import { GetItemId, useSelectorOptions } from "@/utilities";
import { faCheck, faUndo } from "@fortawesome/free-solid-svg-icons";
import { Box, Container } from "@mantine/core";
import { uniqBy } from "lodash";
import { useCallback, useMemo, useState } from "react";
import { UseMutationResult } from "react-query";
import { useNavigate } from "react-router-dom";
import { Column, useRowSelect } from "react-table";
interface MassEditorProps<T extends Item.Base = Item.Base> {
columns: Column<T>[];
data: T[];
mutation: UseMutationResult<void, unknown, FormType.ModifyItem>;
}
function MassEditor<T extends Item.Base>(props: MassEditorProps<T>) {
const { columns, data: raw, mutation } = props;
const [selections, setSelections] = useState<T[]>([]);
const [dirties, setDirties] = useState<T[]>([]);
const hasTask = useIsAnyMutationRunning();
const { data: profiles } = useLanguageProfiles();
const navigate = useNavigate();
const onEnded = useCallback(() => navigate(".."), [navigate]);
const data = useMemo(
() => uniqBy([...dirties, ...(raw ?? [])], GetItemId),
[dirties, raw],
);
const profileOptions = useSelectorOptions(profiles ?? [], (v) => v.name);
const profileOptionsWithAction = useMemo<SelectorOption<Language.Profile>[]>(
() => [...profileOptions.options],
[profileOptions.options],
);
const getKey = useCallback((value: Language.Profile | null) => {
if (value) {
return value.name;
}
return "Clear";
}, []);
const { mutateAsync } = mutation;
const save = useCallback(() => {
const form: FormType.ModifyItem = {
id: [],
profileid: [],
};
dirties.forEach((v) => {
const id = GetItemId(v);
if (id) {
form.id.push(id);
form.profileid.push(v.profileId);
}
});
return mutateAsync(form);
}, [dirties, mutateAsync]);
const setProfiles = useCallback(
(profile: Language.Profile | null) => {
const id = profile?.profileId ?? null;
const newItems = selections.map((v) => ({ ...v, profileId: id }));
setDirties((dirty) => {
return uniqBy([...newItems, ...dirty], GetItemId);
});
},
[selections],
);
return (
<Container fluid px={0}>
<Toolbox>
<Box>
<Selector
allowDeselect
placeholder="Change Profile"
options={profileOptionsWithAction}
getkey={getKey}
disabled={selections.length === 0}
onChange={setProfiles}
></Selector>
</Box>
<Box>
<Toolbox.Button icon={faUndo} onClick={onEnded}>
Cancel
</Toolbox.Button>
<Toolbox.MutateButton
icon={faCheck}
disabled={dirties.length === 0 || hasTask}
promise={save}
onSuccess={onEnded}
>
Save
</Toolbox.MutateButton>
</Box>
</Toolbox>
<SimpleTable
columns={columns}
data={data}
onSelect={setSelections}
plugins={[useRowSelect, useCustomSelection]}
></SimpleTable>
</Container>
);
}
export default MassEditor;