Enable Date edition on People view (#105)

* Enable Date edition on People view

* Fix linter
This commit is contained in:
Charles Bochet
2023-05-05 18:52:04 +02:00
committed by GitHub
parent b8cd842633
commit 406e1dc02e
11 changed files with 372 additions and 8 deletions

View File

@ -0,0 +1,86 @@
import styled from '@emotion/styled';
import { forwardRef, useState } from 'react';
import ReactDatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
export type DatePickerProps = {
isOpen?: boolean;
date: Date;
onChangeHandler: (date: Date) => void;
};
const StyledContainer = styled.div`
& .react-datepicker {
border-color: ${(props) => props.theme.primaryBorder};
font-family: 'Inter';
}
& .react-datepicker__triangle::after {
display: none;
}
& .react-datepicker__triangle::before {
display: none;
}
& .react-datepicker__header {
background-color: ${(props) => props.theme.primaryBackground};
border-bottom-color: ${(props) => props.theme.primaryBorder};
}
& .react-datepicker__day--selected {
background-color: ${(props) => props.theme.blue};
}
`;
function DatePicker({ date, onChangeHandler, isOpen }: DatePickerProps) {
const [startDate, setStartDate] = useState(date);
type DivProps = React.HTMLProps<HTMLDivElement>;
const DateDisplay = forwardRef<HTMLDivElement, DivProps>(
({ value, onClick }, ref) => (
<div onClick={onClick} ref={ref}>
{value &&
new Intl.DateTimeFormat(undefined, {
month: 'short',
day: 'numeric',
year: 'numeric',
}).format(new Date(value as string))}
</div>
),
);
return (
<StyledContainer>
<ReactDatePicker
open={isOpen}
selected={startDate}
onChange={(date: Date) => {
setStartDate(date);
onChangeHandler(date);
}}
popperPlacement="bottom"
popperModifiers={[
{
name: 'offset',
options: {
offset: [55, 0],
},
},
{
name: 'preventOverflow',
options: {
rootBoundary: 'viewport',
tether: false,
altAxis: true,
},
},
]}
customInput={<DateDisplay />}
/>
</StyledContainer>
);
}
export default DatePicker;

View File

@ -0,0 +1,36 @@
import DatePicker, { DatePickerProps } from '../DatePicker';
import { ThemeProvider } from '@emotion/react';
import { lightTheme } from '../../../layout/styles/themes';
import { StoryFn } from '@storybook/react';
import styled from '@emotion/styled';
const component = {
title: 'DatePicker',
component: DatePicker,
};
export default component;
const StyledContainer = styled.div`
height: 300px;
width: 200px;
}`;
const Template: StoryFn<typeof DatePicker> = (args: DatePickerProps) => {
return (
<ThemeProvider theme={lightTheme}>
<StyledContainer>
<DatePicker {...args} />
</StyledContainer>
</ThemeProvider>
);
};
export const DatePickerStory = Template.bind({});
DatePickerStory.args = {
isOpen: true,
date: new Date(),
onChangeHandler: () => {
console.log('changed');
},
};

View File

@ -0,0 +1,22 @@
import { fireEvent, render } from '@testing-library/react';
import { DatePickerStory } from '../__stories__/Datepicker.stories';
import { act } from 'react-dom/test-utils';
it('Checks the datepicker renders', () => {
const changeHandler = jest.fn();
const { getByText } = render(
<DatePickerStory
date={new Date('2021-03-03')}
onChangeHandler={changeHandler}
/>,
);
act(() => {
fireEvent.click(getByText('Mar 3, 2021'));
});
expect(getByText('March 2021')).toBeInTheDocument();
act(() => {
fireEvent.click(getByText('5'));
});
expect(changeHandler).toHaveBeenCalledWith(new Date('2021-03-05'));
});

View File

@ -0,0 +1,47 @@
import styled from '@emotion/styled';
import { useState } from 'react';
import EditableCellWrapper from './EditableCellWrapper';
import DatePicker from '../../form/DatePicker';
export type EditableDateProps = {
value: Date;
changeHandler: (date: Date) => void;
shouldAlignRight?: boolean;
};
const StyledContainer = styled.div`
display: flex;
align-items: center;
`;
function EditableDate({
value,
changeHandler,
shouldAlignRight,
}: EditableDateProps) {
const [inputValue, setInputValue] = useState(value);
const [isEditMode, setIsEditMode] = useState(false);
const onEditModeChange = (isEditMode: boolean) => {
setIsEditMode(isEditMode);
};
return (
<EditableCellWrapper
onEditModeChange={onEditModeChange}
shouldAlignRight={shouldAlignRight}
>
<StyledContainer>
<DatePicker
isOpen={isEditMode}
date={inputValue}
onChangeHandler={(date: Date) => {
changeHandler(date);
setInputValue(date);
}}
/>
</StyledContainer>
</EditableCellWrapper>
);
}
export default EditableDate;

View File

@ -26,7 +26,7 @@ const StyledInplaceInput = styled.input<StyledEditModeProps>`
`;
const StyledNoEditText = styled.div`
max-width: 200px;
width: 100%;
`;
function EditableText({

View File

@ -0,0 +1,29 @@
import EditableDate, { EditableDateProps } from '../EditableDate';
import { ThemeProvider } from '@emotion/react';
import { lightTheme } from '../../../../layout/styles/themes';
import { StoryFn } from '@storybook/react';
const component = {
title: 'EditableDate',
component: EditableDate,
};
export default component;
const Template: StoryFn<typeof EditableDate> = (args: EditableDateProps) => {
return (
<ThemeProvider theme={lightTheme}>
<div data-testid="content-editable-parent">
<EditableDate {...args} />
</div>
</ThemeProvider>
);
};
export const EditableDateStory = Template.bind({});
EditableDateStory.args = {
value: new Date(),
changeHandler: () => {
console.log('changed');
},
};

View File

@ -0,0 +1,37 @@
import { fireEvent, render } from '@testing-library/react';
import { EditableDateStory } from '../__stories__/EditableDate.stories';
import { act } from 'react-dom/test-utils';
it('Checks the EditableDate editing event bubbles up', async () => {
const changeHandler = jest.fn(() => null);
const { getByTestId, getByText } = render(
<EditableDateStory
value={new Date('2021-03-03')}
changeHandler={changeHandler}
/>,
);
const parent = getByTestId('content-editable-parent');
const wrapper = parent.querySelector('div');
if (!wrapper) {
throw new Error('Cell Wrapper not found');
}
act(() => {
fireEvent.click(wrapper);
});
const dateDisplay = parent.querySelector('div');
if (!dateDisplay) {
throw new Error('Editable input not found');
}
expect(getByText('March 2021')).toBeInTheDocument();
act(() => {
fireEvent.click(getByText('5'));
});
expect(changeHandler).toHaveBeenCalledWith(new Date('2021-03-05'));
});