Enable Date edition on People view (#105)
* Enable Date edition on People view * Fix linter
This commit is contained in:
86
front/src/components/form/DatePicker.tsx
Normal file
86
front/src/components/form/DatePicker.tsx
Normal 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;
|
||||
36
front/src/components/form/__stories__/Datepicker.stories.tsx
Normal file
36
front/src/components/form/__stories__/Datepicker.stories.tsx
Normal 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');
|
||||
},
|
||||
};
|
||||
22
front/src/components/form/__tests__/Datepicker.test.tsx
Normal file
22
front/src/components/form/__tests__/Datepicker.test.tsx
Normal 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'));
|
||||
});
|
||||
47
front/src/components/table/editable-cell/EditableDate.tsx
Normal file
47
front/src/components/table/editable-cell/EditableDate.tsx
Normal 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;
|
||||
@ -26,7 +26,7 @@ const StyledInplaceInput = styled.input<StyledEditModeProps>`
|
||||
`;
|
||||
|
||||
const StyledNoEditText = styled.div`
|
||||
max-width: 200px;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
function EditableText({
|
||||
|
||||
@ -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');
|
||||
},
|
||||
};
|
||||
@ -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'));
|
||||
});
|
||||
Reference in New Issue
Block a user