diff --git a/rsconcept/frontend/src/components/ui/DataTable/DataTable.tsx b/rsconcept/frontend/src/components/ui/DataTable/DataTable.tsx index bbd51cd6..a7bf9683 100644 --- a/rsconcept/frontend/src/components/ui/DataTable/DataTable.tsx +++ b/rsconcept/frontend/src/components/ui/DataTable/DataTable.tsx @@ -100,6 +100,7 @@ function DataTable({ ...restProps }: DataTableProps) { const [sorting, setSorting] = useState(initialSorting ? [initialSorting] : []); + const [lastSelected, setLastSelected] = useState(undefined); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -147,6 +148,7 @@ function DataTable({ enableRowSelection={enableRowSelection} enableSorting={enableSorting} headPosition={headPosition} + setLastSelected={setLastSelected} /> ) : null} @@ -155,6 +157,8 @@ function DataTable({ dense={dense} conditionalRowStyles={conditionalRowStyles} enableRowSelection={enableRowSelection} + lastSelected={lastSelected} + setLastSelected={setLastSelected} onRowClicked={onRowClicked} onRowDoubleClicked={onRowDoubleClicked} /> diff --git a/rsconcept/frontend/src/components/ui/DataTable/SelectAll.tsx b/rsconcept/frontend/src/components/ui/DataTable/SelectAll.tsx index 5d72bc50..c7da72bd 100644 --- a/rsconcept/frontend/src/components/ui/DataTable/SelectAll.tsx +++ b/rsconcept/frontend/src/components/ui/DataTable/SelectAll.tsx @@ -4,9 +4,15 @@ import CheckboxTristate from '@/components/ui/CheckboxTristate'; interface SelectAllProps { table: Table; + setLastSelected: React.Dispatch>; } -function SelectAll({ table }: SelectAllProps) { +function SelectAll({ table, setLastSelected }: SelectAllProps) { + function handleChange(value: boolean | null) { + setLastSelected(undefined); + table.toggleAllPageRowsSelected(value !== false); + } + return ( ({ table }: SelectAllProps) { value={ !table.getIsAllPageRowsSelected() && table.getIsSomePageRowsSelected() ? null : table.getIsAllPageRowsSelected() } - setValue={value => table.toggleAllPageRowsSelected(value !== false)} + setValue={handleChange} /> ); } diff --git a/rsconcept/frontend/src/components/ui/DataTable/SelectRow.tsx b/rsconcept/frontend/src/components/ui/DataTable/SelectRow.tsx index ee66ef8e..b0a673c2 100644 --- a/rsconcept/frontend/src/components/ui/DataTable/SelectRow.tsx +++ b/rsconcept/frontend/src/components/ui/DataTable/SelectRow.tsx @@ -4,10 +4,16 @@ import Checkbox from '@/components/ui/Checkbox'; interface SelectRowProps { row: Row; + setLastSelected: React.Dispatch>; } -function SelectRow({ row }: SelectRowProps) { - return ; +function SelectRow({ row, setLastSelected }: SelectRowProps) { + function handleChange(value: boolean) { + setLastSelected(row.id); + row.toggleSelected(value); + } + + return ; } export default SelectRow; diff --git a/rsconcept/frontend/src/components/ui/DataTable/TableBody.tsx b/rsconcept/frontend/src/components/ui/DataTable/TableBody.tsx index 8a56e9c1..d91c26fd 100644 --- a/rsconcept/frontend/src/components/ui/DataTable/TableBody.tsx +++ b/rsconcept/frontend/src/components/ui/DataTable/TableBody.tsx @@ -8,6 +8,10 @@ interface TableBodyProps { dense?: boolean; enableRowSelection?: boolean; conditionalRowStyles?: IConditionalStyle[]; + + lastSelected: string | undefined; + setLastSelected: React.Dispatch>; + onRowClicked?: (rowData: TData, event: React.MouseEvent) => void; onRowDoubleClicked?: (rowData: TData, event: React.MouseEvent) => void; } @@ -17,15 +21,34 @@ function TableBody({ dense, enableRowSelection, conditionalRowStyles, + lastSelected, + setLastSelected, onRowClicked, onRowDoubleClicked }: TableBodyProps) { - function handleRowClicked(row: Row, event: React.MouseEvent) { + function handleRowClicked(target: Row, event: React.MouseEvent) { if (onRowClicked) { - onRowClicked(row.original, event); + onRowClicked(target.original, event); } - if (enableRowSelection && row.getCanSelect()) { - row.getToggleSelectedHandler()(!row.getIsSelected()); + if (enableRowSelection && target.getCanSelect()) { + if (event.shiftKey && !!lastSelected && lastSelected !== target.id) { + const { rows, rowsById } = table.getRowModel(); + const lastIndex = rowsById[lastSelected].index; + const currentIndex = target.index; + const toggleRows = rows.slice( + lastIndex > currentIndex ? currentIndex : lastIndex + 1, + lastIndex > currentIndex ? lastIndex : currentIndex + 1 + ); + const newSelection: { [key: string]: boolean } = {}; + toggleRows.forEach(row => { + newSelection[row.id] = !target.getIsSelected(); + }); + table.setRowSelection(prev => ({ ...prev, ...newSelection })); + setLastSelected(undefined); + } else { + setLastSelected(target.id); + target.toggleSelected(!target.getIsSelected()); + } } } @@ -53,7 +76,7 @@ function TableBody({ > {enableRowSelection ? ( - + ) : null} {row.getVisibleCells().map((cell: Cell) => ( diff --git a/rsconcept/frontend/src/components/ui/DataTable/TableHeader.tsx b/rsconcept/frontend/src/components/ui/DataTable/TableHeader.tsx index 200725bd..e3825885 100644 --- a/rsconcept/frontend/src/components/ui/DataTable/TableHeader.tsx +++ b/rsconcept/frontend/src/components/ui/DataTable/TableHeader.tsx @@ -8,9 +8,16 @@ interface TableHeaderProps { headPosition?: string; enableRowSelection?: boolean; enableSorting?: boolean; + setLastSelected: React.Dispatch>; } -function TableHeader({ table, headPosition, enableRowSelection, enableSorting }: TableHeaderProps) { +function TableHeader({ + table, + headPosition, + enableRowSelection, + enableSorting, + setLastSelected +}: TableHeaderProps) { return ( ({ table, headPosition, enableRowSelection, enableSor {enableRowSelection ? ( - + ) : null} {headerGroup.headers.map((header: Header) => ( diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/EditorRSList.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/EditorRSList.tsx index b7bac5e8..b99bd578 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/EditorRSList.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/EditorRSList.tsx @@ -3,8 +3,8 @@ import clsx from 'clsx'; import { useLayoutEffect, useMemo, useState } from 'react'; -import { type RowSelectionState } from '@/components/ui/DataTable'; import SelectedCounter from '@/components/info/SelectedCounter'; +import { type RowSelectionState } from '@/components/ui/DataTable'; import { useConceptTheme } from '@/context/ThemeContext'; import { ConstituentaID, CstType } from '@/models/rsform';