Lucas/refactored table state with recoil (#149)

* Fixed ActionBar paddings and added transition on button hover

* Added recoil library for state management

* Refactor table state with recoil :

- Removed table internal states
- Added refetchQueries to plug apollo store directly into tables
- Added an action bar component that manages itself
- Use recoil state and selector for row selection
- Refactored Companies and People tables

* Moved hook

* Cleaned some files

* Fix bug infinite re-compute table row selection

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Lucas Bordeau
2023-05-27 08:41:26 +02:00
committed by GitHub
parent 9a3aa1d3d2
commit 8f88605f32
20 changed files with 238 additions and 212 deletions

View File

@ -1,39 +0,0 @@
import styled from '@emotion/styled';
import ActionBarButton from './ActionBarButton';
import { TbTrash } from 'react-icons/tb';
type OwnProps = {
onDeleteClick: () => void;
};
const StyledContainer = styled.div`
display: flex;
position: absolute;
z-index: 1;
height: 48px;
bottom: 38px;
background: ${(props) => props.theme.secondaryBackground};
align-items: center;
padding-left: ${(props) => props.theme.spacing(4)};
padding-right: ${(props) => props.theme.spacing(4)};
color: ${(props) => props.theme.red};
left: 50%;
transform: translateX(-50%);
border-radius: 8px;
border: 1px solid ${(props) => props.theme.primaryBorder};
`;
function ActionBar({ onDeleteClick }: OwnProps) {
return (
<StyledContainer>
<ActionBarButton
label="Delete"
icon={<TbTrash size={16} />}
onClick={onDeleteClick}
/>
</StyledContainer>
);
}
export default ActionBar;

View File

@ -0,0 +1,36 @@
import styled from '@emotion/styled';
import React from 'react';
import { useRecoilValue } from 'recoil';
import { selectedRowIdsState } from '../../../modules/ui/tables/states/selectedRowIdsState';
type OwnProps = {
children: React.ReactNode | React.ReactNode[];
};
const StyledContainer = styled.div`
display: flex;
position: absolute;
z-index: 1;
height: 48px;
bottom: 38px;
background: ${(props) => props.theme.secondaryBackground};
align-items: center;
padding-left: ${(props) => props.theme.spacing(2)};
padding-right: ${(props) => props.theme.spacing(2)};
color: ${(props) => props.theme.red};
left: 50%;
transform: translateX(-50%);
border-radius: 8px;
border: 1px solid ${(props) => props.theme.primaryBorder};
`;
export function EntityTableActionBar({ children }: OwnProps) {
const selectedRowIds = useRecoilValue(selectedRowIdsState);
if (selectedRowIds.length === 0) {
return <></>;
}
return <StyledContainer>{children}</StyledContainer>;
}

View File

@ -16,6 +16,7 @@ const StyledButton = styled.div`
padding: ${(props) => props.theme.spacing(2)};
border-radius: 4px;
transition: background 0.1s ease;
&:hover {
background: ${(props) => props.theme.tertiaryBackground};
@ -27,7 +28,7 @@ const StyledButtonLabel = styled.div`
font-weight: 500;
`;
function ActionBarButton({ label, icon, onClick }: OwnProps) {
export function EntityTableActionBarButton({ label, icon, onClick }: OwnProps) {
return (
<StyledButton onClick={onClick}>
{icon}
@ -35,5 +36,3 @@ function ActionBarButton({ label, icon, onClick }: OwnProps) {
</StyledButton>
);
}
export default ActionBarButton;

View File

@ -1,30 +0,0 @@
import ActionBar from '../ActionBar';
import { ThemeProvider } from '@emotion/react';
import { lightTheme } from '../../../../layout/styles/themes';
import { StoryFn } from '@storybook/react';
const component = {
title: 'ActionBar',
component: ActionBar,
};
type OwnProps = {
onDeleteClick: () => void;
};
export default component;
const Template: StoryFn<typeof ActionBar> = (args: OwnProps) => {
return (
<ThemeProvider theme={lightTheme}>
<ActionBar {...args} />
</ThemeProvider>
);
};
export const ActionBarStory = Template.bind({});
ActionBarStory.args = {
onDeleteClick: () => {
console.log('deleted');
},
};

View File

@ -1,17 +0,0 @@
import { fireEvent, render } from '@testing-library/react';
import { ActionBarStory } from '../__stories__/ActionBar.stories';
import { act } from 'react-dom/test-utils';
it('Checks the ActionBar editing event bubbles up', async () => {
const deleteFunc = jest.fn(() => null);
const { getByText } = render(<ActionBarStory onDeleteClick={deleteFunc} />);
expect(getByText('Delete')).toBeInTheDocument();
act(() => {
fireEvent.click(getByText('Delete'));
});
expect(deleteFunc).toHaveBeenCalled();
});