diff --git a/front/src/components/form/Checkbox.tsx b/front/src/components/form/Checkbox.tsx index 05781e0e7..86aee19bf 100644 --- a/front/src/components/form/Checkbox.tsx +++ b/front/src/components/form/Checkbox.tsx @@ -6,13 +6,17 @@ type OwnProps = { id: string; checked?: boolean; indeterminate?: boolean; - onChange?: (event: React.ChangeEvent) => void; + onChange?: (newCheckedValue: boolean) => void; }; -const StyledContainer = styled.span` +const StyledContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; + input[type='checkbox'] { accent-color: ${(props) => props.theme.blue}; - margin: 8px; + margin: 2px; height: 14px; width: 14px; cursor: pointer; @@ -37,8 +41,15 @@ const StyledContainer = styled.span` } `; -function Checkbox({ name, id, checked, onChange, indeterminate }: OwnProps) { +export function Checkbox({ + name, + id, + checked, + onChange, + indeterminate, +}: OwnProps) { const ref = React.useRef(null); + React.useEffect(() => { if (ref.current === null) return; if (typeof indeterminate === 'boolean') { @@ -46,6 +57,12 @@ function Checkbox({ name, id, checked, onChange, indeterminate }: OwnProps) { } }, [ref, indeterminate, checked]); + function handleInputChange(event: React.ChangeEvent) { + if (onChange) { + onChange(event.target.checked); + } + } + return ( ); } - -export default Checkbox; diff --git a/front/src/components/table/CheckboxCell.tsx b/front/src/components/table/CheckboxCell.tsx new file mode 100644 index 000000000..aae1e543f --- /dev/null +++ b/front/src/components/table/CheckboxCell.tsx @@ -0,0 +1,65 @@ +import * as React from 'react'; +import styled from '@emotion/styled'; +import { Checkbox } from '../form/Checkbox'; + +type OwnProps = { + name: string; + id: string; + checked?: boolean; + indeterminate?: boolean; + onChange?: (newCheckedValue: boolean) => void; +}; + +const StyledContainer = styled.div` + width: 32px; + height: 32px; + margin-left: -${(props) => props.theme.table.horizontalCellMargin}; + padding-left: ${(props) => props.theme.table.horizontalCellMargin}; + + display: flex; + align-items: center; + justify-content: center; + + cursor: pointer; +`; + +export function CheckboxCell({ + name, + id, + checked, + onChange, + indeterminate, +}: OwnProps) { + const [internalChecked, setInternalChecked] = React.useState(checked); + + function handleContainerClick() { + handleCheckboxChange(!internalChecked); + } + + React.useEffect(() => { + setInternalChecked(checked); + }, [checked]); + + function handleCheckboxChange(newCheckedValue: boolean) { + setInternalChecked(newCheckedValue); + + if (onChange) { + onChange(newCheckedValue); + } + } + + return ( + + + + ); +} diff --git a/front/src/components/table/EntityTable.tsx b/front/src/components/table/EntityTable.tsx index df8b10e10..18f9145a0 100644 --- a/front/src/components/table/EntityTable.tsx +++ b/front/src/components/table/EntityTable.tsx @@ -34,12 +34,12 @@ type OwnProps< const StyledTable = styled.table` min-width: 1000px; - width: calc(100% - ${(props) => props.theme.spacing(4)}); + width: calc(100% - 2 * ${(props) => props.theme.table.horizontalCellMargin}); border-radius: 4px; border-spacing: 0; border-collapse: collapse; - margin-left: ${(props) => props.theme.spacing(2)}; - margin-right: ${(props) => props.theme.spacing(2)}; + margin-left: ${(props) => props.theme.table.horizontalCellMargin}; + margin-right: ${(props) => props.theme.table.horizontalCellMargin}; table-layout: fixed; th { diff --git a/front/src/components/table/SelectAllCheckbox.tsx b/front/src/components/table/SelectAllCheckbox.tsx index bc88856e8..005d91104 100644 --- a/front/src/components/table/SelectAllCheckbox.tsx +++ b/front/src/components/table/SelectAllCheckbox.tsx @@ -1,14 +1,14 @@ -import Checkbox from '../form/Checkbox'; +import { CheckboxCell } from './CheckboxCell'; export const SelectAllCheckbox = ({ indeterminate, onChange, }: { indeterminate?: boolean; - onChange?: any; + onChange?: (newCheckedValue: boolean) => void; } & React.HTMLProps) => { return ( - `${multiplicator * 4}px`, + + table: { + horizontalCellMargin: '8px', + }, }; const lightThemeSpecific = { diff --git a/front/src/pages/companies/companies-columns.tsx b/front/src/pages/companies/companies-columns.tsx index 67ffe877d..80b9879b6 100644 --- a/front/src/pages/companies/companies-columns.tsx +++ b/front/src/pages/companies/companies-columns.tsx @@ -9,7 +9,6 @@ import { updateCompany } from '../../services/api/companies'; import { User, mapToUser } from '../../interfaces/entities/user.interface'; import ColumnHead from '../../components/table/ColumnHead'; -import Checkbox from '../../components/form/Checkbox'; import { SelectAllCheckbox } from '../../components/table/SelectAllCheckbox'; import EditableDate from '../../components/editable-cell/EditableDate'; import EditableRelation from '../../components/editable-cell/EditableRelation'; @@ -29,6 +28,7 @@ import { } from 'react-icons/tb'; import { QueryMode } from '../../generated/graphql'; import { getLogoUrlFromDomainName } from '../../services/utils'; +import { CheckboxCell } from '../../components/table/CheckboxCell'; const columnHelper = createColumnHelper(); @@ -41,15 +41,15 @@ export const useCompaniesColumns = () => { table.toggleAllRowsSelected(newValue)} /> ), cell: (props: CellContext) => ( - props.row.toggleSelected(newValue)} /> ), size: 25, diff --git a/front/src/pages/people/__stories__/People.inputs.stories.tsx b/front/src/pages/people/__stories__/People.inputs.stories.tsx index b64429c28..d308fd777 100644 --- a/front/src/pages/people/__stories__/People.inputs.stories.tsx +++ b/front/src/pages/people/__stories__/People.inputs.stories.tsx @@ -6,6 +6,7 @@ import People from '../People'; import { Story } from './People.stories'; import { mocks, render } from './shared'; import { mockedPeopleData } from '../../../testing/mock-data/people'; +import { sleep } from '../../../testing/sleep'; const meta: Meta = { title: 'Pages/People', @@ -39,7 +40,7 @@ export const ChangeEmail: Story = { await userEvent.click(secondRowEmailCell); - await new Promise((resolve) => setTimeout(resolve, 25)); + await sleep(25); expect( canvas.queryByTestId('editable-cell-edit-mode-container'), @@ -47,7 +48,7 @@ export const ChangeEmail: Story = { await userEvent.click(secondRowEmailCell); - await new Promise((resolve) => setTimeout(resolve, 25)); + await sleep(25); expect( canvas.queryByTestId('editable-cell-edit-mode-container'), @@ -57,3 +58,34 @@ export const ChangeEmail: Story = { msw: mocks, }, }; + +export const Checkbox: Story = { + render, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + await sleep(500); + + const inputCheckboxContainers = await canvas.findAllByTestId( + 'input-checkbox-cell-container', + ); + + const inputCheckboxes = await canvas.findAllByTestId('input-checkbox'); + + const secondCheckboxContainer = inputCheckboxContainers[1]; + const secondCheckbox = inputCheckboxes[1] as HTMLInputElement; + + expect(secondCheckboxContainer).toBeDefined(); + + await userEvent.click(secondCheckboxContainer); + + expect(secondCheckbox.checked).toBe(true); + + await userEvent.click(secondCheckbox); + + expect(secondCheckbox.checked).toBe(false); + }, + parameters: { + msw: mocks, + }, +}; diff --git a/front/src/pages/people/people-columns.tsx b/front/src/pages/people/people-columns.tsx index 1752bbb1d..03ed3ee54 100644 --- a/front/src/pages/people/people-columns.tsx +++ b/front/src/pages/people/people-columns.tsx @@ -4,7 +4,6 @@ import { Person } from '../../interfaces/entities/person.interface'; import { updatePerson } from '../../services/api/people'; import ColumnHead from '../../components/table/ColumnHead'; -import Checkbox from '../../components/form/Checkbox'; import { SelectAllCheckbox } from '../../components/table/SelectAllCheckbox'; import EditablePhone from '../../components/editable-cell/EditablePhone'; import { EditablePeopleFullName } from '../../components/people/EditablePeopleFullName'; @@ -19,6 +18,7 @@ import { TbUser, } from 'react-icons/tb'; import { PeopleCompanyCell } from '../../components/people/PeopleCompanyCell'; +import { CheckboxCell } from '../../components/table/CheckboxCell'; const columnHelper = createColumnHelper(); @@ -31,15 +31,15 @@ export const usePeopleColumns = () => { table.toggleAllRowsSelected(newValue)} /> ), cell: (props: CellContext) => ( - props.row.toggleSelected(newValue)} /> ), size: 25, diff --git a/front/src/testing/sleep.ts b/front/src/testing/sleep.ts new file mode 100644 index 000000000..ab5262d54 --- /dev/null +++ b/front/src/testing/sleep.ts @@ -0,0 +1,5 @@ +export async function sleep(ms: number) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +}