Fix/table remove and mock data (#653)

* Removed tanstack react table

* Fixed remove table feature without tanstack table

* Fixed delete people and companies

* Fixed hotkeys on editable date cell

* Fixed double text

* Fixed company mock mode

* Fixed lint

* Fixed right click selection
This commit is contained in:
Lucas Bordeau
2023-07-13 21:43:00 +02:00
committed by GitHub
parent e8bd3b7a14
commit d70234f918
21 changed files with 132 additions and 111 deletions

View File

@ -8,7 +8,7 @@ import { useSetHotkeysScope } from '@/hotkeys/hooks/useSetHotkeysScope';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { GET_PEOPLE } from '@/people/services';
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
import { selectedRowIdsState } from '@/ui/tables/states/selectedRowIdsState';
import { selectedRowIdsSelector } from '@/ui/tables/states/selectedRowIdsSelector';
import {
CommentableType,
useCreateCommentThreadMutation,
@ -36,7 +36,7 @@ export function useOpenCreateCommentThreadDrawerForSelectedRowIds() {
commentableEntityArrayState,
);
const selectedEntityIds = useRecoilValue(selectedRowIdsState);
const selectedEntityIds = useRecoilValue(selectedRowIdsSelector);
return function openCreateCommentDrawerForSelectedRowIds(
entityType: CommentableType,

View File

@ -0,0 +1,36 @@
import { useEffect } from 'react';
import { useRecoilState } from 'recoil';
import { isFetchingEntityTableDataState } from '@/ui/tables/states/isFetchingEntityTableDataState';
import { tableRowIdsState } from '@/ui/tables/states/tableRowIdsState';
import { mockedCompaniesData } from '~/testing/mock-data/companies';
import { useSetCompanyEntityTable } from '../hooks/useSetCompanyEntityTable';
export function CompanyEntityTableDataMocked() {
const [, setTableRowIds] = useRecoilState(tableRowIdsState);
const [, setIsFetchingEntityTableData] = useRecoilState(
isFetchingEntityTableDataState,
);
const setCompanyEntityTable = useSetCompanyEntityTable();
useEffect(() => {
const companyIds = mockedCompaniesData.map((company) => company.id);
setTableRowIds((currentRowIds) => {
if (JSON.stringify(currentRowIds) !== JSON.stringify(companyIds)) {
return companyIds;
}
return currentRowIds;
});
setCompanyEntityTable(mockedCompaniesData);
setIsFetchingEntityTableData(false);
}, [setCompanyEntityTable, setIsFetchingEntityTableData, setTableRowIds]);
return <></>;
}

View File

@ -1,3 +1,7 @@
import { Key } from 'ts-key-enum';
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
import { InplaceInputDateEditMode } from '@/ui/inplace-inputs/components/InplaceInputDateEditMode';
import { useEditableCell } from '../hooks/useEditableCell';
@ -18,5 +22,14 @@ export function EditableCellDateEditMode({
closeEditableCell();
}
useScopedHotkeys(
Key.Escape,
() => {
closeEditableCell();
},
InternalHotkeysScope.CellDateEditMode,
[closeEditableCell],
);
return <InplaceInputDateEditMode onChange={handleDateChange} value={value} />;
}

View File

@ -1,4 +1,4 @@
import { ReactElement, useState } from 'react';
import { ReactElement, useEffect, useState } from 'react';
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
@ -29,6 +29,11 @@ export function EditableCellDoubleText({
const [firstInternalValue, setFirstInternalValue] = useState(firstValue);
const [secondInternalValue, setSecondInternalValue] = useState(secondValue);
useEffect(() => {
setFirstInternalValue(firstValue);
setSecondInternalValue(secondValue);
}, [firstValue, secondValue]);
function handleOnChange(firstValue: string, secondValue: string): void {
setFirstInternalValue(firstValue);
setSecondInternalValue(secondValue);

View File

@ -17,17 +17,13 @@ export function EntityTableBody({ columns }: { columns: Array<TableColumn> }) {
return (
<tbody>
{!isFetchingEntityTableData ? (
rowIds.map((rowId, index) => (
<RecoilScope SpecificContext={RowContext} key={rowId}>
<EntityTableRow columns={columns} rowId={rowId} index={index} />
</RecoilScope>
))
) : (
<tr>
<td>loading...</td>
</tr>
)}
{!isFetchingEntityTableData
? rowIds.map((rowId, index) => (
<RecoilScope SpecificContext={RowContext} key={rowId}>
<EntityTableRow columns={columns} rowId={rowId} index={index} />
</RecoilScope>
))
: null}
</tbody>
);
}

View File

@ -1,11 +1,11 @@
import { useEffect } from 'react';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { useSetRecoilState } from 'recoil';
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
import { useCurrentRowSelected } from '@/ui/tables/hooks/useCurrentRowSelected';
import { CellContext } from '@/ui/tables/states/CellContext';
import { contextMenuPositionState } from '@/ui/tables/states/contextMenuPositionState';
import { currentColumnNumberScopedState } from '@/ui/tables/states/currentColumnNumberScopedState';
import { currentRowSelectionState } from '@/ui/tables/states/rowSelectionState';
export function EntityTableCell({
rowId,
@ -18,8 +18,6 @@ export function EntityTableCell({
cellIndex: number;
children: React.ReactNode;
}) {
const [, setCurrentRowSelection] = useRecoilState(currentRowSelectionState);
const [, setCurrentColumnNumber] = useRecoilScopedState(
currentColumnNumberScopedState,
CellContext,
@ -31,9 +29,12 @@ export function EntityTableCell({
const setContextMenuPosition = useSetRecoilState(contextMenuPositionState);
function handleContextMenu(event: React.MouseEvent, id: string) {
const { setCurrentRowSelected } = useCurrentRowSelected();
function handleContextMenu(event: React.MouseEvent) {
event.preventDefault();
setCurrentRowSelection((prev) => ({ ...prev, [id]: true }));
setCurrentRowSelected(true);
setContextMenuPosition({
x: event.clientX,
@ -43,7 +44,7 @@ export function EntityTableCell({
return (
<td
onContextMenu={(event) => handleContextMenu(event, rowId)}
onContextMenu={(event) => handleContextMenu(event)}
style={{
width: size,
minWidth: size,

View File

@ -1,6 +1,6 @@
import { useEffect } from 'react';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { useRecoilValue } from 'recoil';
import { TableColumn } from '@/people/table/components/peopleColumns';
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
@ -8,8 +8,8 @@ import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'
import { CellContext } from '@/ui/tables/states/CellContext';
import { currentRowEntityIdScopedState } from '@/ui/tables/states/currentRowEntityIdScopedState';
import { currentRowNumberScopedState } from '@/ui/tables/states/currentRowNumberScopedState';
import { isRowSelectedFamilyState } from '@/ui/tables/states/isRowSelectedFamilyState';
import { RowContext } from '@/ui/tables/states/RowContext';
import { currentRowSelectionState } from '@/ui/tables/states/rowSelectionState';
import { CheckboxCell } from './CheckboxCell';
import { EntityTableCell } from './EntityTableCell';
@ -28,12 +28,13 @@ export function EntityTableRow({
rowId: string;
index: number;
}) {
const [currentRowSelection] = useRecoilState(currentRowSelectionState);
const [currentRowEntityId, setCurrentRowEntityId] = useRecoilScopedState(
currentRowEntityIdScopedState,
RowContext,
);
const isCurrentRowSelected = useRecoilValue(isRowSelectedFamilyState(rowId));
const [, setCurrentRowNumber] = useRecoilScopedState(
currentRowNumberScopedState,
RowContext,
@ -53,7 +54,7 @@ export function EntityTableRow({
<StyledRow
key={rowId}
data-testid={`row-id-${rowId}`}
selected={!!currentRowSelection[rowId]}
selected={isCurrentRowSelected}
>
<td>
<CheckboxCell />

View File

@ -2,14 +2,14 @@ import React from 'react';
import { useRecoilValue } from 'recoil';
import { ActionBar } from '@/ui/components/action-bar/ActionBar';
import { selectedRowIdsState } from '@/ui/tables/states/selectedRowIdsState';
import { selectedRowIdsSelector } from '@/ui/tables/states/selectedRowIdsSelector';
type OwnProps = {
children: React.ReactNode | React.ReactNode[];
};
export function EntityTableActionBar({ children }: OwnProps) {
const selectedRowIds = useRecoilValue(selectedRowIdsState);
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
return <ActionBar selectedIds={selectedRowIds}>{children}</ActionBar>;
}

View File

@ -1,7 +1,6 @@
import { useRecoilCallback, useRecoilState } from 'recoil';
import { isRowSelectedFamilyState } from '../states/isRowSelectedFamilyState';
import { numberOfSelectedRowState } from '../states/numberOfSelectedRowState';
import { useCurrentRowEntityId } from './useCurrentEntityId';
@ -21,15 +20,9 @@ export function useCurrentRowSelected() {
.getLoadable(isRowSelectedFamilyState(currentRowId))
.valueOrThrow();
const numberOfSelectedRow = snapshot
.getLoadable(numberOfSelectedRowState)
.valueOrThrow();
if (newSelectedState && !isRowSelected) {
set(numberOfSelectedRowState, numberOfSelectedRow + 1);
set(isRowSelectedFamilyState(currentRowId), true);
} else if (!newSelectedState && isRowSelected) {
set(numberOfSelectedRowState, numberOfSelectedRow - 1);
set(isRowSelectedFamilyState(currentRowId), false);
}
},

View File

@ -1,17 +1,20 @@
import { useCallback } from 'react';
import { useSetRecoilState } from 'recoil';
import { useRecoilCallback } from 'recoil';
import { currentRowSelectionState } from '../states/rowSelectionState';
import { isRowSelectedFamilyState } from '../states/isRowSelectedFamilyState';
import { tableRowIdsState } from '../states/tableRowIdsState';
export function useResetTableRowSelection() {
const setCurrentRowSelectionState = useSetRecoilState(
currentRowSelectionState,
);
return useRecoilCallback(
({ snapshot, set }) =>
() => {
const tableRowIds = snapshot
.getLoadable(tableRowIdsState)
.valueOrThrow();
return useCallback(
function resetCurrentRowSelection() {
setCurrentRowSelectionState({});
},
[setCurrentRowSelectionState],
for (const rowId of tableRowIds) {
set(isRowSelectedFamilyState(rowId), false);
}
},
[],
);
}

View File

@ -2,8 +2,6 @@ import { useRecoilCallback, useRecoilValue } from 'recoil';
import { allRowsSelectedStatusSelector } from '../states/allRowsSelectedStatusSelector';
import { isRowSelectedFamilyState } from '../states/isRowSelectedFamilyState';
import { numberOfSelectedRowState } from '../states/numberOfSelectedRowState';
import { numberOfTableRowsSelectorState } from '../states/numberOfTableRowsSelectorState';
import { tableRowIdsState } from '../states/tableRowIdsState';
export function useSelectAllRows() {
@ -16,23 +14,15 @@ export function useSelectAllRows() {
.getLoadable(allRowsSelectedStatusSelector)
.valueOrThrow();
const numberOfRows = snapshot
.getLoadable(numberOfTableRowsSelectorState)
.valueOrThrow();
const tableRowIds = snapshot
.getLoadable(tableRowIdsState)
.valueOrThrow();
if (allRowsSelectedStatus === 'none') {
set(numberOfSelectedRowState, numberOfRows);
for (const rowId of tableRowIds) {
set(isRowSelectedFamilyState(rowId), true);
}
} else {
set(numberOfSelectedRowState, 0);
for (const rowId of tableRowIds) {
set(isRowSelectedFamilyState(rowId), false);
}

View File

@ -2,15 +2,17 @@ import { selector } from 'recoil';
import { AllRowsSelectedStatus } from '../types/AllRowSelectedStatus';
import { numberOfSelectedRowState } from './numberOfSelectedRowState';
import { numberOfTableRowsSelectorState } from './numberOfTableRowsSelectorState';
import { selectedRowIdsSelector } from './selectedRowIdsSelector';
export const allRowsSelectedStatusSelector = selector<AllRowsSelectedStatus>({
key: 'allRowsSelectedStatusSelector',
get: ({ get }) => {
const numberOfRows = get(numberOfTableRowsSelectorState);
const numberOfSelectedRows = get(numberOfSelectedRowState);
const selectedRowIds = get(selectedRowIdsSelector);
const numberOfSelectedRows = selectedRowIds.length;
const allRowsSelectedStatus =
numberOfSelectedRows === 0

View File

@ -1,6 +0,0 @@
import { atom } from 'recoil';
export const numberOfSelectedRowState = atom<number>({
key: 'numberOfSelectedRowState',
default: 0,
});

View File

@ -1,7 +0,0 @@
import { RowSelectionState } from '@tanstack/react-table';
import { atom } from 'recoil';
export const currentRowSelectionState = atom<RowSelectionState>({
key: 'currentRowSelectionState',
default: {},
});

View File

@ -0,0 +1,15 @@
import { selector } from 'recoil';
import { isRowSelectedFamilyState } from './isRowSelectedFamilyState';
import { tableRowIdsState } from './tableRowIdsState';
export const selectedRowIdsSelector = selector<string[]>({
key: 'selectedRowIdsSelector',
get: ({ get }) => {
const rowIds = get(tableRowIdsState);
return rowIds.filter(
(rowId) => get(isRowSelectedFamilyState(rowId)) === true,
);
},
});

View File

@ -1,14 +0,0 @@
import { selector } from 'recoil';
import { currentRowSelectionState } from './rowSelectionState';
export const selectedRowIdsState = selector<string[]>({
key: 'selectedRowIdsState',
get: ({ get }) => {
const currentRowSelection = get(currentRowSelectionState);
return Object.keys(currentRowSelection).filter(
(key) => currentRowSelection[key] === true,
);
},
});

View File

@ -1,6 +1,7 @@
import { IconList } from '@tabler/icons-react';
import { companyColumns } from '@/companies/table/components/companyColumns';
import { CompanyEntityTableDataMocked } from '@/companies/table/components/CompanyEntityTableDataMocked';
import { EntityTable } from '@/ui/components/table/EntityTable';
import { HooksEntityTable } from '@/ui/components/table/HooksEntityTable';
@ -10,6 +11,7 @@ import { availableSorts } from './companies-sorts';
export function CompanyTableMockMode() {
return (
<>
<CompanyEntityTableDataMocked />
<HooksEntityTable
numberOfColumns={companyColumns.length}
availableFilters={companiesFilters}

View File

@ -5,11 +5,11 @@ import { GET_COMPANIES } from '@/companies/services';
import { EntityTableActionBarButton } from '@/ui/components/table/action-bar/EntityTableActionBarButton';
import { IconTrash } from '@/ui/icons/index';
import { useResetTableRowSelection } from '@/ui/tables/hooks/useResetTableRowSelection';
import { selectedRowIdsState } from '@/ui/tables/states/selectedRowIdsState';
import { selectedRowIdsSelector } from '@/ui/tables/states/selectedRowIdsSelector';
import { useDeleteCompaniesMutation } from '~/generated/graphql';
export function TableActionBarButtonDeleteCompanies() {
const selectedRowIds = useRecoilValue(selectedRowIdsState);
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
const resetRowSelection = useResetTableRowSelection();
@ -18,13 +18,15 @@ export function TableActionBarButtonDeleteCompanies() {
});
async function handleDeleteClick() {
await deleteCompanies({
variables: {
ids: selectedRowIds,
},
});
const rowIdsToDelete = selectedRowIds;
resetRowSelection();
await deleteCompanies({
variables: {
ids: rowIdsToDelete,
},
});
}
return (

View File

@ -5,11 +5,11 @@ import { GET_PEOPLE } from '@/people/services';
import { EntityTableActionBarButton } from '@/ui/components/table/action-bar/EntityTableActionBarButton';
import { IconTrash } from '@/ui/icons/index';
import { useResetTableRowSelection } from '@/ui/tables/hooks/useResetTableRowSelection';
import { selectedRowIdsState } from '@/ui/tables/states/selectedRowIdsState';
import { selectedRowIdsSelector } from '@/ui/tables/states/selectedRowIdsSelector';
import { useDeletePeopleMutation } from '~/generated/graphql';
export function TableActionBarButtonDeletePeople() {
const selectedRowIds = useRecoilValue(selectedRowIdsState);
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
const resetRowSelection = useResetTableRowSelection();
@ -18,13 +18,15 @@ export function TableActionBarButtonDeletePeople() {
});
async function handleDeleteClick() {
await deletePeople({
variables: {
ids: selectedRowIds,
},
});
const rowIdsToDelete = selectedRowIds;
resetRowSelection();
await deletePeople({
variables: {
ids: rowIdsToDelete,
},
});
}
return (