Skip to content

Commit b292f2b

Browse files
author
karabij
committed
✨(frontend) add meeting register form
add a form which enables the user to register the meeting
1 parent 26278f4 commit b292f2b

File tree

31 files changed

+1050
-298
lines changed

31 files changed

+1050
-298
lines changed

src/frontend/magnify/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@testing-library/react": "13.3.0",
3737
"@testing-library/user-event": "14.2.1",
3838
"@types/jest": "28.1.1",
39+
"@types/luxon": "^3.1.0",
3940
"@types/react": "18.0.12",
4041
"@types/react-time-picker": "^4.0.2",
4142
"@types/styled-components": "5.1.25",
@@ -57,6 +58,7 @@
5758
"jest": "28.1.1",
5859
"jest-css-modules": "2.1.0",
5960
"jest-environment-jsdom": "28.1.1",
61+
"luxon": "^3.1.1",
6062
"msw": "0.47.4",
6163
"postcss": "8.4.14",
6264
"prettier": "2.7.0",

src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/FormikDatePicker.stories.tsx

Lines changed: 0 additions & 24 deletions
This file was deleted.

src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/FormikDatePicker.tsx

Lines changed: 0 additions & 102 deletions
This file was deleted.

src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import withFormik from '@bbbtech/storybook-formik';
2+
import { ComponentMeta, ComponentStory } from '@storybook/react';
3+
import React from 'react';
4+
import FormikDateTimePicker from './FormikDateTimePicker';
5+
6+
export default {
7+
title: 'Formik/DateTimePicker',
8+
component: FormikDateTimePicker,
9+
decorators: [withFormik],
10+
initialValues: { date: new Date() },
11+
} as ComponentMeta<typeof FormikDateTimePicker>;
12+
13+
const Template: ComponentStory<typeof FormikDateTimePicker> = (args, context) => (
14+
<div>
15+
{context.parameters.title}
16+
<FormikDateTimePicker {...args} />
17+
</div>
18+
);
19+
20+
export const basicDateTimePicker = Template.bind({});
21+
22+
basicDateTimePicker.args = {
23+
timeName: 'time',
24+
dateName: 'date',
25+
frenchSuggestions: ['14:00', '15:00'],
26+
localTimeSuggestions: ['2:00 PM', '3:00 PM'],
27+
};
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { ErrorMessage, useField, useFormikContext } from 'formik';
2+
import { DateInput, DropButton, Box, Text } from 'grommet';
3+
import { CaretDown } from 'grommet-icons';
4+
import { DateTime, Settings } from 'luxon';
5+
import React, { FunctionComponent, useState } from 'react';
6+
import { useIntl } from 'react-intl';
7+
import TimePicker, { TimePickerValue } from 'react-time-picker';
8+
import SuggestionButton from './SuggestionButton';
9+
10+
export interface formikDateTimePickerProps {
11+
dateName: string;
12+
timeName: string;
13+
frenchSuggestions: string[];
14+
localTimeSuggestions: string[];
15+
label: string;
16+
}
17+
18+
const nextYear = new Date();
19+
nextYear.setFullYear(new Date().getFullYear() + 1);
20+
21+
const FormikDateTimePicker: FunctionComponent<formikDateTimePickerProps> = ({ ...props }) => {
22+
const [open, setOpen] = useState<boolean | undefined>(undefined);
23+
const [dateField] = useField(props.dateName);
24+
const [timeField] = useField(props.timeName);
25+
26+
const formikContext = useFormikContext();
27+
const intl = useIntl();
28+
Settings.defaultLocale = intl.locale;
29+
30+
const isToday =
31+
DateTime.fromISO(dateField.value).toFormat('MM-dd-yyyy') ==
32+
DateTime.now().toFormat('MM-dd-yyyy');
33+
const beforeToday =
34+
DateTime.fromISO(dateField.value).toFormat('MM-dd-yyyy') <
35+
DateTime.now().toFormat('MM-dd-yyyy');
36+
37+
const onTimeChange = (value: string | undefined) => {
38+
formikContext.setFieldValue(props.timeName, value ? value.toString() : undefined);
39+
setOpen(false);
40+
};
41+
42+
const onDateChange = (event: { value: string | string[] }) => {
43+
let value: string;
44+
if (Array.isArray(event.value)) {
45+
value = '';
46+
if (event.value.length > 0) {
47+
value = event.value[0];
48+
}
49+
} else {
50+
value = event.value;
51+
}
52+
formikContext.setFieldValue(props.dateName, value);
53+
};
54+
55+
React.useEffect(() => {
56+
console.log(formikContext.errors, formikContext.values);
57+
}, [formikContext.values, formikContext.errors]);
58+
59+
const suggestionButtons = props.localTimeSuggestions.map((value: string, index: number) => (
60+
<SuggestionButton
61+
key={value}
62+
beforeToday={beforeToday}
63+
buttonValue={value}
64+
choiceValue={timeField.value}
65+
frenchButtonValue={props.frenchSuggestions[index]}
66+
isToday={isToday}
67+
onClick={onTimeChange}
68+
/>
69+
));
70+
71+
return (
72+
<Box gap={'5px'}>
73+
{props.label != '' && (
74+
<label htmlFor={props.dateName}>
75+
<Text size={'xsmall'} weight={'bold'}>
76+
{props.label}
77+
</Text>
78+
</label>
79+
)}
80+
<div>
81+
<Box align="center" basis="1" direction="column" gap="small">
82+
<DateInput
83+
{...dateField}
84+
format={intl.locale === 'fr' ? 'jj/mm/aaaa' : 'yyyy/mm/dd'}
85+
name={props.dateName}
86+
onChange={onDateChange}
87+
calendarProps={{
88+
bounds: [new Date().toISOString(), nextYear.toISOString()],
89+
size: 'small',
90+
}}
91+
></DateInput>
92+
93+
<Box align="center" direction="row" gap="small">
94+
<TimePicker
95+
{...timeField}
96+
disableClock
97+
locale={intl.locale}
98+
name={props.timeName}
99+
onChange={(value: TimePickerValue) =>
100+
onTimeChange(value ? value.toString() : undefined)
101+
}
102+
></TimePicker>
103+
<DropButton
104+
dropAlign={{ top: 'bottom' }}
105+
onClose={() => setOpen(false)}
106+
open={open}
107+
dropContent={
108+
<Box align="center" basis="small" direction="column" gap="5px">
109+
{suggestionButtons}
110+
</Box>
111+
}
112+
onOpen={() => {
113+
setOpen(true);
114+
}}
115+
>
116+
<CaretDown size="15px" />
117+
</DropButton>
118+
</Box>
119+
</Box>
120+
</div>
121+
</Box>
122+
);
123+
};
124+
125+
export default FormikDateTimePicker;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Box, Button, Text } from 'grommet';
2+
import { normalizeColor } from 'grommet/utils';
3+
import { DateTime } from 'luxon';
4+
import React, { FunctionComponent, ReactElement } from 'react';
5+
import { useTheme } from 'styled-components';
6+
import { mergeDateTime } from './utils';
7+
8+
const today = DateTime.now().toISO();
9+
10+
export interface suggestionButtonProps {
11+
buttonValue: string;
12+
frenchButtonValue: string;
13+
choiceValue: string;
14+
onClick: (value: string) => void;
15+
isToday: boolean;
16+
beforeToday: boolean;
17+
}
18+
19+
const SuggestionButton: FunctionComponent<suggestionButtonProps> = ({ ...props }): ReactElement => {
20+
const isChosenButton: boolean = props.frenchButtonValue == props.choiceValue;
21+
const chosenDateTime = mergeDateTime(today, props.frenchButtonValue);
22+
const isButtonBeforeNow: boolean = chosenDateTime ? chosenDateTime < today : false;
23+
const theme = useTheme();
24+
return (
25+
<Button
26+
color={isChosenButton ? `${normalizeColor('light-2', theme)}` : 'black'}
27+
disabled={props.beforeToday || (props.isToday && isButtonBeforeNow)}
28+
fill={isChosenButton ? 'horizontal' : false}
29+
justify="center"
30+
margin={{ top: 'xsmall' }}
31+
primary={isChosenButton}
32+
onClick={() => {
33+
props.onClick(props.frenchButtonValue);
34+
console.log(`chosenDateTime : ${chosenDateTime}`);
35+
}}
36+
>
37+
<Box alignContent="center" alignSelf="center">
38+
<Text color="black" textAlign="center">
39+
{props.buttonValue}
40+
</Text>
41+
</Box>
42+
</Button>
43+
);
44+
};
45+
46+
export default SuggestionButton;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default, formikDateTimePickerProps } from '../FormikDateTimePicker/FormikDateTimePicker';
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { DateTime, Duration } from 'luxon';
2+
3+
export const splitDateTime = (dateTimeISO: string | null): { date: string; time: string } => {
4+
if (!dateTimeISO) {
5+
return { date: '', time: '' };
6+
}
7+
const dateTime = DateTime.fromISO(dateTimeISO);
8+
return {
9+
date: dateTime.toISODate(),
10+
time: dateTime.toLocaleString(DateTime.TIME_24_SIMPLE),
11+
};
12+
};
13+
14+
export const mergeDateTime = (
15+
dateString: string | null,
16+
timeString: string | null,
17+
): string | null => {
18+
if (!dateString || !timeString) {
19+
return null;
20+
}
21+
try {
22+
const time = Duration.fromISOTime(timeString);
23+
const dateTime = DateTime.fromISO(dateString).set({
24+
hour: time.hours,
25+
minute: time.minutes,
26+
});
27+
return dateTime.toISO();
28+
} catch (e) {
29+
return null;
30+
}
31+
};

0 commit comments

Comments
 (0)