Refactor constituenta move functionality

This commit is contained in:
IRBorisov 2024-02-03 15:49:23 +03:00
parent 2b7a4c04ce
commit a5f3539798
4 changed files with 97 additions and 58 deletions

View File

@ -1,7 +1,7 @@
'use client';
import { useMemo } from 'react';
import { BiDuplicate, BiPlusCircle, BiReset, BiTrash } from 'react-icons/bi';
import { BiDownvote, BiDuplicate, BiPlusCircle, BiReset, BiTrash, BiUpvote } from 'react-icons/bi';
import { FiSave } from 'react-icons/fi';
import HelpButton from '@/components/Help/HelpButton';
@ -16,6 +16,8 @@ interface ConstituentaToolbarProps {
onSubmit: () => void;
onReset: () => void;
onMoveUp: () => void;
onMoveDown: () => void;
onDelete: () => void;
onClone: () => void;
onCreate: () => void;
@ -26,6 +28,8 @@ function ConstituentaToolbar({
isModified,
onSubmit,
onReset,
onMoveUp,
onMoveDown,
onDelete,
onClone,
onCreate
@ -63,6 +67,18 @@ function ConstituentaToolbar({
onClick={onDelete}
icon={<BiTrash size='1.25rem' className={isMutable ? 'clr-text-warning' : ''} />}
/>
<MiniButton
title='Переместить вверх [Alt + вверх]'
icon={<BiUpvote size='1.25rem' className={isMutable ? 'clr-text-primary' : ''} />}
disabled={!isMutable}
onClick={onMoveUp}
/>
<MiniButton
title='Переместить вниз [Alt + вниз]'
icon={<BiDownvote size='1.25rem' className={isMutable ? 'clr-text-primary' : ''} />}
disabled={!isMutable}
onClick={onMoveDown}
/>
<HelpButton topic={HelpTopic.CONSTITUENTA} offset={4} />
</Overlay>
);

View File

@ -26,6 +26,8 @@ interface EditorConstituentaProps {
isModified: boolean;
setIsModified: React.Dispatch<React.SetStateAction<boolean>>;
onMoveUp: () => void;
onMoveDown: () => void;
onOpenEdit: (cstID: number) => void;
onClone: () => void;
onCreate: (type?: CstType) => void;
@ -40,11 +42,13 @@ function EditorConstituenta({
isModified,
setIsModified,
activeCst,
onEditTerm,
onMoveUp,
onMoveDown,
onOpenEdit,
onClone,
onCreate,
onRename,
onOpenEdit,
onEditTerm,
onDelete
}: EditorConstituentaProps) {
const windowSize = useWindowSize();
@ -99,6 +103,8 @@ function EditorConstituenta({
<ConstituentaToolbar
isMutable={!disabled}
isModified={isModified}
onMoveUp={onMoveUp}
onMoveDown={onMoveDown}
onSubmit={initiateSubmit}
onReset={() => setToggleReset(prev => !prev)}
onDelete={onDelete}

View File

@ -4,16 +4,18 @@ import { useLayoutEffect, useState } from 'react';
import { type RowSelectionState } from '@/components/DataTable';
import SelectedCounter from '@/components/SelectedCounter';
import { useRSForm } from '@/context/RSFormContext';
import { CstType, ICstMovetoData } from '@/models/rsform';
import { CstType, IRSForm } from '@/models/rsform';
import RSListToolbar from './RSListToolbar';
import RSTable from './RSTable';
interface EditorRSListProps {
schema?: IRSForm;
isMutable: boolean;
selected: number[];
setSelected: React.Dispatch<React.SetStateAction<number[]>>;
onMoveUp: () => void;
onMoveDown: () => void;
onOpenEdit: (cstID: number) => void;
onClone: () => void;
onCreate: (type?: CstType) => void;
@ -21,16 +23,17 @@ interface EditorRSListProps {
}
function EditorRSList({
schema,
selected,
setSelected,
isMutable,
onMoveUp,
onMoveDown,
onOpenEdit,
onClone,
onCreate,
onDelete
}: EditorRSListProps) {
const { schema, cstMoveTo } = useRSForm();
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
useLayoutEffect(() => {
@ -60,52 +63,6 @@ function EditorRSList({
}
}
// Move selected cst up
function handleMoveUp() {
if (!schema?.items || selected.length === 0) {
return;
}
const currentIndex = schema.items.reduce((prev, cst, index) => {
if (!selected.includes(cst.id)) {
return prev;
} else if (prev === -1) {
return index;
}
return Math.min(prev, index);
}, -1);
const target = Math.max(0, currentIndex - 1) + 1;
const data = {
items: selected,
move_to: target
};
cstMoveTo(data);
}
// Move selected cst down
function handleMoveDown() {
if (!schema?.items || selected.length === 0) {
return;
}
let count = 0;
const currentIndex = schema.items.reduce((prev, cst, index) => {
if (!selected.includes(cst.id)) {
return prev;
} else {
count += 1;
if (prev === -1) {
return index;
}
return Math.max(prev, index);
}
}, -1);
const target = Math.min(schema.items.length - 1, currentIndex - count + 2) + 1;
const data: ICstMovetoData = {
items: selected,
move_to: target
};
cstMoveTo(data);
}
// Implement hotkeys for working with constituents table
function handleTableKey(event: React.KeyboardEvent<HTMLDivElement>) {
if (!isMutable) {
@ -129,8 +86,8 @@ function EditorRSList({
if (selected.length > 0) {
// prettier-ignore
switch (code) {
case 'ArrowUp': handleMoveUp(); return true;
case 'ArrowDown': handleMoveDown(); return true;
case 'ArrowUp': onMoveUp(); return true;
case 'ArrowDown': onMoveDown(); return true;
case 'KeyV': onClone(); return true;
}
}
@ -161,8 +118,8 @@ function EditorRSList({
<RSListToolbar
selectedCount={selected.length}
isMutable={isMutable}
onMoveUp={handleMoveUp}
onMoveDown={handleMoveDown}
onMoveUp={onMoveUp}
onMoveDown={onMoveDown}
onClone={onClone}
onCreate={onCreate}
onDelete={onDelete}

View File

@ -28,7 +28,15 @@ import DlgRenameCst from '@/dialogs/DlgRenameCst';
import DlgUploadRSForm from '@/dialogs/DlgUploadRSForm';
import useQueryStrings from '@/hooks/useQueryStrings';
import { UserAccessMode } from '@/models/miscellaneous';
import { CstType, IConstituenta, ICstCreateData, ICstRenameData, ICstUpdateData, TermForm } from '@/models/rsform';
import {
CstType,
IConstituenta,
ICstCreateData,
ICstMovetoData,
ICstRenameData,
ICstUpdateData,
TermForm
} from '@/models/rsform';
import { generateAlias } from '@/models/rsformAPI';
import { EXTEOR_TRS_FILE, prefixes, TIMEOUT_UI_REFRESH } from '@/utils/constants';
@ -66,6 +74,7 @@ function RSTabs() {
subscribe,
unsubscribe,
cstUpdate,
cstMoveTo,
resetAliases
} = useRSForm();
const { destroyItem } = useLibrary();
@ -262,6 +271,52 @@ function RSTabs() {
const onReindex = useCallback(() => resetAliases(() => toast.success('Имена конституент обновлены')), [resetAliases]);
// Move selected cst up
function handleMoveUp() {
if (!schema?.items || selected.length === 0) {
return;
}
const currentIndex = schema.items.reduce((prev, cst, index) => {
if (!selected.includes(cst.id)) {
return prev;
} else if (prev === -1) {
return index;
}
return Math.min(prev, index);
}, -1);
const target = Math.max(0, currentIndex - 1) + 1;
const data = {
items: selected,
move_to: target
};
cstMoveTo(data);
}
// Move selected cst down
function handleMoveDown() {
if (!schema?.items || selected.length === 0) {
return;
}
let count = 0;
const currentIndex = schema.items.reduce((prev, cst, index) => {
if (!selected.includes(cst.id)) {
return prev;
} else {
count += 1;
if (prev === -1) {
return index;
}
return Math.max(prev, index);
}
}, -1);
const target = Math.min(schema.items.length - 1, currentIndex - count + 2) + 1;
const data: ICstMovetoData = {
items: selected,
move_to: target
};
cstMoveTo(data);
}
const handleDeleteCst = useCallback(
(deleted: number[]) => {
if (!schema) {
@ -479,9 +534,12 @@ function RSTabs() {
<TabPanel forceRender style={{ display: activeTab === RSTabID.CST_LIST ? '' : 'none' }}>
<EditorRSList
schema={schema}
selected={selected}
setSelected={setSelected}
isMutable={isMutable}
onMoveUp={handleMoveUp}
onMoveDown={handleMoveDown}
onOpenEdit={onOpenCst}
onClone={handleCloneCst}
onCreate={type => promptCreateCst(type, type !== undefined)}
@ -496,6 +554,8 @@ function RSTabs() {
isModified={isModified}
setIsModified={setIsModified}
activeCst={activeCst}
onMoveUp={handleMoveUp}
onMoveDown={handleMoveDown}
onOpenEdit={onOpenCst}
onClone={handleCloneCst}
onCreate={type => promptCreateCst(type, false)}