Enable multi-selection on table views (#112)
* Enable multi-selection on table views * Enable multi-selection
This commit is contained in:
@ -4,6 +4,9 @@ import styled from '@emotion/styled';
|
|||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
name: string;
|
name: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
checked?: boolean;
|
||||||
|
indeterminate?: boolean;
|
||||||
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledContainer = styled.span`
|
const StyledContainer = styled.span`
|
||||||
@ -28,14 +31,25 @@ const StyledContainer = styled.span`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function Checkbox({ name, id }: OwnProps) {
|
function Checkbox({ name, id, checked, onChange, indeterminate }: OwnProps) {
|
||||||
|
const ref = React.useRef<HTMLInputElement>(null);
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (ref.current === null) return;
|
||||||
|
if (typeof indeterminate === 'boolean') {
|
||||||
|
ref.current.indeterminate = !checked && indeterminate;
|
||||||
|
}
|
||||||
|
}, [ref, indeterminate, checked]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<input
|
<input
|
||||||
|
ref={ref}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
data-testid="input-checkbox"
|
data-testid="input-checkbox"
|
||||||
id={id}
|
id={id}
|
||||||
name={name}
|
name={name}
|
||||||
|
checked={checked}
|
||||||
|
onChange={onChange}
|
||||||
></input>
|
></input>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
18
front/src/components/table/SelectAllCheckbox.tsx
Normal file
18
front/src/components/table/SelectAllCheckbox.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import Checkbox from '../form/Checkbox';
|
||||||
|
|
||||||
|
export const SelectAllCheckbox = ({
|
||||||
|
indeterminate,
|
||||||
|
onChange,
|
||||||
|
}: {
|
||||||
|
indeterminate?: boolean;
|
||||||
|
onChange?: any;
|
||||||
|
} & React.HTMLProps<HTMLInputElement>) => {
|
||||||
|
return (
|
||||||
|
<Checkbox
|
||||||
|
name="select-all-checkbox"
|
||||||
|
id="select-all-checkbox"
|
||||||
|
indeterminate={indeterminate}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -2,6 +2,7 @@ import * as React from 'react';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
|
RowSelectionState,
|
||||||
flexRender,
|
flexRender,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
useReactTable,
|
useReactTable,
|
||||||
@ -34,6 +35,7 @@ type OwnProps<TData, SortField, FilterProperties> = {
|
|||||||
filter: FilterType<FilterProperties> | null,
|
filter: FilterType<FilterProperties> | null,
|
||||||
searchValue: string,
|
searchValue: string,
|
||||||
) => void;
|
) => void;
|
||||||
|
onRowSelectionChange?: (rowSelection: RowSelectionState) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledTable = styled.table`
|
const StyledTable = styled.table`
|
||||||
@ -98,11 +100,23 @@ function Table<TData extends { id: string }, SortField, FilterProperies>({
|
|||||||
onSortsUpdate,
|
onSortsUpdate,
|
||||||
onFiltersUpdate,
|
onFiltersUpdate,
|
||||||
onFilterSearch,
|
onFilterSearch,
|
||||||
|
onRowSelectionChange,
|
||||||
}: OwnProps<TData, SortField, FilterProperies>) {
|
}: OwnProps<TData, SortField, FilterProperies>) {
|
||||||
|
const [rowSelection, setRowSelection] = React.useState({});
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
onRowSelectionChange && onRowSelectionChange(rowSelection);
|
||||||
|
}, [rowSelection, onRowSelectionChange]);
|
||||||
|
|
||||||
const table = useReactTable<TData>({
|
const table = useReactTable<TData>({
|
||||||
data,
|
data,
|
||||||
columns,
|
columns,
|
||||||
|
state: {
|
||||||
|
rowSelection,
|
||||||
|
},
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
enableRowSelection: true, //enable row selection for all rows
|
||||||
|
onRowSelectionChange: setRowSelection,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -99,6 +99,9 @@ function Companies() {
|
|||||||
setSearhInput(searchValue);
|
setSearhInput(searchValue);
|
||||||
setFilterSearch(filter);
|
setFilterSearch(filter);
|
||||||
}}
|
}}
|
||||||
|
onRowSelectionChange={(selectedRows) => {
|
||||||
|
console.log(selectedRows);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</StyledCompaniesContainer>
|
</StyledCompaniesContainer>
|
||||||
</WithTopBarContainer>
|
</WithTopBarContainer>
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
import { createColumnHelper } from '@tanstack/react-table';
|
import { CellContext, createColumnHelper } from '@tanstack/react-table';
|
||||||
import {
|
import {
|
||||||
Company,
|
Company,
|
||||||
GraphqlQueryCompany,
|
GraphqlQueryCompany,
|
||||||
} from '../../interfaces/company.interface';
|
} from '../../interfaces/company.interface';
|
||||||
import { updateCompany } from '../../services/companies';
|
import { updateCompany } from '../../services/companies';
|
||||||
import ColumnHead from '../../components/table/ColumnHead';
|
import ColumnHead from '../../components/table/ColumnHead';
|
||||||
import Checkbox from '../../components/form/Checkbox';
|
|
||||||
import CompanyChip from '../../components/chips/CompanyChip';
|
import CompanyChip from '../../components/chips/CompanyChip';
|
||||||
import EditableText from '../../components/table/editable-cell/EditableText';
|
import EditableText from '../../components/table/editable-cell/EditableText';
|
||||||
import {
|
import {
|
||||||
@ -39,6 +38,8 @@ import EditableDate from '../../components/table/editable-cell/EditableDate';
|
|||||||
import EditableRelation from '../../components/table/editable-cell/EditableRelation';
|
import EditableRelation from '../../components/table/editable-cell/EditableRelation';
|
||||||
import { GraphqlQueryUser, PartialUser } from '../../interfaces/user.interface';
|
import { GraphqlQueryUser, PartialUser } from '../../interfaces/user.interface';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { SelectAllCheckbox } from '../../components/table/SelectAllCheckbox';
|
||||||
|
import Checkbox from '../../components/form/Checkbox';
|
||||||
|
|
||||||
export const availableSorts = [
|
export const availableSorts = [
|
||||||
{
|
{
|
||||||
@ -141,17 +142,24 @@ const columnHelper = createColumnHelper<Company>();
|
|||||||
export const useCompaniesColumns = () => {
|
export const useCompaniesColumns = () => {
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return [
|
return [
|
||||||
columnHelper.accessor('id', {
|
{
|
||||||
header: () => (
|
id: 'select',
|
||||||
<Checkbox id="company-select-all" name="company-select-all" />
|
header: ({ table }: any) => (
|
||||||
|
<SelectAllCheckbox
|
||||||
|
checked={table.getIsAllRowsSelected()}
|
||||||
|
indeterminate={table.getIsSomeRowsSelected()}
|
||||||
|
onChange={table.getToggleAllRowsSelectedHandler()}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
cell: (props) => (
|
cell: (props: CellContext<Company, string>) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id={`company-selected-${props.row.original.id}`}
|
id={`company-selected-${props.row.original.id}`}
|
||||||
name={`company-selected-${props.row.original.id}`}
|
name={`company-selected-${props.row.original.id}`}
|
||||||
|
checked={props.row.getIsSelected()}
|
||||||
|
onChange={props.row.getToggleSelectedHandler()}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
}),
|
},
|
||||||
columnHelper.accessor('name', {
|
columnHelper.accessor('name', {
|
||||||
header: () => (
|
header: () => (
|
||||||
<ColumnHead viewName="Name" viewIcon={<FaRegBuilding />} />
|
<ColumnHead viewName="Name" viewIcon={<FaRegBuilding />} />
|
||||||
|
|||||||
@ -98,6 +98,9 @@ function People() {
|
|||||||
setSearchInput(searchValue);
|
setSearchInput(searchValue);
|
||||||
setFilterSearch(filter);
|
setFilterSearch(filter);
|
||||||
}}
|
}}
|
||||||
|
onRowSelectionChange={(selectedRows) => {
|
||||||
|
console.log(selectedRows);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</StyledPeopleContainer>
|
</StyledPeopleContainer>
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import {
|
|||||||
FaUser,
|
FaUser,
|
||||||
FaBuilding,
|
FaBuilding,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import { createColumnHelper } from '@tanstack/react-table';
|
import { CellContext, createColumnHelper } from '@tanstack/react-table';
|
||||||
import ColumnHead from '../../components/table/ColumnHead';
|
import ColumnHead from '../../components/table/ColumnHead';
|
||||||
import Checkbox from '../../components/form/Checkbox';
|
import Checkbox from '../../components/form/Checkbox';
|
||||||
import CompanyChip, {
|
import CompanyChip, {
|
||||||
@ -39,6 +39,7 @@ import EditableDate from '../../components/table/editable-cell/EditableDate';
|
|||||||
import EditableRelation from '../../components/table/editable-cell/EditableRelation';
|
import EditableRelation from '../../components/table/editable-cell/EditableRelation';
|
||||||
import { updatePerson } from '../../services/people';
|
import { updatePerson } from '../../services/people';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { SelectAllCheckbox } from '../../components/table/SelectAllCheckbox';
|
||||||
|
|
||||||
export const availableSorts = [
|
export const availableSorts = [
|
||||||
{
|
{
|
||||||
@ -247,17 +248,24 @@ const columnHelper = createColumnHelper<Person>();
|
|||||||
export const usePeopleColumns = () => {
|
export const usePeopleColumns = () => {
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return [
|
return [
|
||||||
columnHelper.accessor('id', {
|
{
|
||||||
header: () => (
|
id: 'select',
|
||||||
<Checkbox id={`person-select-all`} name={`person-select-all`} />
|
header: ({ table }: any) => (
|
||||||
),
|
<SelectAllCheckbox
|
||||||
cell: (props) => (
|
checked={table.getIsAllRowsSelected()}
|
||||||
<Checkbox
|
indeterminate={table.getIsSomeRowsSelected()}
|
||||||
id={`person-selected-${props.row.original.email}`}
|
onChange={table.getToggleAllRowsSelectedHandler()}
|
||||||
name={`person-selected-${props.row.original.email}`}
|
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
}),
|
cell: (props: CellContext<Person, string>) => (
|
||||||
|
<Checkbox
|
||||||
|
id={`person-selected-${props.row.original.id}`}
|
||||||
|
name={`person-selected-${props.row.original.id}`}
|
||||||
|
checked={props.row.getIsSelected()}
|
||||||
|
onChange={props.row.getToggleSelectedHandler()}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
columnHelper.accessor('firstname', {
|
columnHelper.accessor('firstname', {
|
||||||
header: () => <ColumnHead viewName="People" viewIcon={<FaRegUser />} />,
|
header: () => <ColumnHead viewName="People" viewIcon={<FaRegUser />} />,
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
|
|||||||
Reference in New Issue
Block a user