Skip to content

Commit a0b0062

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 a0b0062

30 files changed

Lines changed: 1011 additions & 298 deletions

File tree

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: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import withFormik from '@bbbtech/storybook-formik';
2+
import { ComponentMeta, ComponentStory } from '@storybook/react';
3+
import React from 'react';
4+
import { useIntl } from 'react-intl';
5+
import { getSuggestions } from '../../../meetings/RegisterMeetingForm/utils';
6+
import FormikDateTimePicker from './FormikDateTimePicker';
7+
8+
export default {
9+
title: 'Formik/DateTimePicker',
10+
component: FormikDateTimePicker,
11+
decorators: [withFormik],
12+
initialValues: { date: new Date() },
13+
} as ComponentMeta<typeof FormikDateTimePicker>;
14+
15+
const Template: ComponentStory<typeof FormikDateTimePicker> = (args, context) => (
16+
<div>
17+
{context.parameters.title}
18+
<FormikDateTimePicker {...args} />
19+
</div>
20+
);
21+
22+
export const basicDateTimePicker = Template.bind({});
23+
const intl = useIntl();
24+
25+
basicDateTimePicker.args = {
26+
timeName: 'time',
27+
dateName: 'date',
28+
frenchSuggestions: getSuggestions('fr'),
29+
localTimeSuggestions: getSuggestions(intl.locale),
30+
};
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import { ErrorMessage, useField, useFormikContext } from 'formik';
2+
import { DateInput, DropButton, Box, Text } from 'grommet';
3+
import { DateTime, Settings } from 'luxon';
4+
import React, { FunctionComponent, useState } from 'react';
5+
import { defineMessages, useIntl } from 'react-intl';
6+
import TimePicker, { TimePickerValue } from 'react-time-picker';
7+
import SuggestionButton from './SuggestionButton';
8+
import { mergeDateTime } from './utils';
9+
10+
const messages = defineMessages({
11+
invalidTime: {
12+
defaultMessage: 'Input time is not valid: Starting time should be set in the future.',
13+
description: 'Error message when event scheduling date time update is in the past.',
14+
id: 'components.design-system.Formik.FormikDateTimePicker.invalidTime',
15+
},
16+
});
17+
18+
export interface formikDateTimePickerProps {
19+
dateName: string;
20+
timeName: string;
21+
frenchSuggestions: string[];
22+
localTimeSuggestions: string[];
23+
}
24+
25+
const nextYear = new Date();
26+
nextYear.setFullYear(new Date().getFullYear() + 1);
27+
28+
const FormikDateTimePicker: FunctionComponent<formikDateTimePickerProps> = ({ ...props }) => {
29+
const [open, setOpen] = useState<boolean | undefined>(undefined);
30+
const [dateField] = useField(props.dateName);
31+
const [timeField] = useField(props.timeName);
32+
const [timeError, setTimeError] = useState(false);
33+
34+
const formikContext = useFormikContext();
35+
const intl = useIntl();
36+
Settings.defaultLocale = intl.locale;
37+
38+
const isToday =
39+
DateTime.fromISO(dateField.value).toFormat('MM-dd-yyyy') ==
40+
DateTime.now().toFormat('MM-dd-yyyy');
41+
const beforeToday =
42+
DateTime.fromISO(dateField.value).toFormat('MM-dd-yyyy') <
43+
DateTime.now().toFormat('MM-dd-yyyy');
44+
45+
const onDateChange = (event: { value: string | string[] }) => {
46+
let value: string;
47+
if (Array.isArray(event.value)) {
48+
value = '';
49+
if (event.value.length > 0) {
50+
value = event.value[0];
51+
}
52+
} else {
53+
value = event.value;
54+
}
55+
formikContext.setFieldValue(props.dateName, value);
56+
};
57+
58+
const onTimeChange = (value: TimePickerValue | string) => {
59+
formikContext.setFieldValue(props.timeName, value.toString());
60+
console.log(formikContext.errors, formikContext.values);
61+
};
62+
63+
const determineIfTimeError = () => {
64+
const chosenDateTime = mergeDateTime(dateField.value, timeField.value);
65+
if (
66+
timeField.value == undefined
67+
? new Date(dateField.value).setHours(0, 0, 0, 0) < new Date().setHours(0, 0, 0, 0)
68+
: timeField.value == null
69+
? true
70+
: chosenDateTime
71+
? chosenDateTime < DateTime.local().toISO()
72+
: false
73+
) {
74+
console.log('coucou');
75+
formikContext.setFieldError(props.timeName, 'nein !!');
76+
}
77+
};
78+
79+
const onTimeSelectChange = (value: string) => {
80+
onTimeChange(value);
81+
setOpen(false);
82+
};
83+
84+
React.useEffect(() => {
85+
determineIfTimeError();
86+
console.log(`date: ${dateField.value}`);
87+
console.log(`time:${timeField.value}`);
88+
console.log(`dateTime: ${mergeDateTime(dateField.value, timeField.value)}`);
89+
console.log(formikContext);
90+
}, [dateField.value, timeField.value]);
91+
92+
const suggestionButtons = props.localTimeSuggestions.map((value: string, index: number) => (
93+
<SuggestionButton
94+
key={value}
95+
beforeToday={beforeToday}
96+
buttonValue={value}
97+
choiceValue={timeField.value}
98+
frenchButtonValue={props.frenchSuggestions[index]}
99+
isToday={isToday}
100+
onClick={onTimeSelectChange}
101+
/>
102+
));
103+
104+
return (
105+
<Box>
106+
<DateInput
107+
format={intl.locale === 'fr' ? 'jj/mm/aaaa' : 'yyyy/mm/dd'}
108+
name={props.dateName}
109+
onChange={onDateChange}
110+
value={dateField.value ? new Date(dateField.value).toISOString() : ''}
111+
calendarProps={{
112+
bounds: [new Date().toISOString(), nextYear.toISOString()],
113+
size: 'small',
114+
}}
115+
></DateInput>
116+
<Box align="start" pad="small">
117+
<DropButton
118+
dropAlign={{ top: 'bottom' }}
119+
onClose={() => setOpen(false)}
120+
open={open}
121+
dropContent={
122+
<Box align="center" basis="small" direction="column" gap="5px">
123+
{suggestionButtons}
124+
</Box>
125+
}
126+
onOpen={() => {
127+
setOpen(true);
128+
}}
129+
>
130+
<TimePicker
131+
disableClock
132+
locale={intl.locale}
133+
onChange={onTimeChange}
134+
value={timeField.value}
135+
></TimePicker>
136+
</DropButton>
137+
</Box>
138+
<ErrorMessage
139+
name={props.timeName}
140+
render={(msg: string) => {
141+
return (
142+
<Text color={'accent-1'} size={'xsmall'}>
143+
{msg}
144+
</Text>
145+
);
146+
}}
147+
></ErrorMessage>
148+
</Box>
149+
);
150+
};
151+
152+
export default FormikDateTimePicker;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Box, Button, Text } from 'grommet';
2+
import { normalizeColor } from 'grommet/utils';
3+
import React, { FunctionComponent, ReactElement } from 'react';
4+
import { useTheme } from 'styled-components';
5+
import { mergeDateTime } from './utils';
6+
7+
const today = new Date().toISOString();
8+
9+
export interface suggestionButtonProps {
10+
buttonValue: string;
11+
frenchButtonValue: string;
12+
choiceValue: string;
13+
onClick: (value: string) => void;
14+
isToday: boolean;
15+
beforeToday: boolean;
16+
}
17+
18+
const SuggestionButton: FunctionComponent<suggestionButtonProps> = ({ ...props }): ReactElement => {
19+
const isChosenButton: boolean = props.buttonValue == props.choiceValue;
20+
const chosenDateTime = mergeDateTime(today, props.buttonValue);
21+
const isButtonBeforeNow: boolean = chosenDateTime ? chosenDateTime < today : false;
22+
const theme = useTheme();
23+
return (
24+
<Button
25+
color={isChosenButton ? `${normalizeColor('light-2', theme)}` : 'black'}
26+
disabled={props.beforeToday || (props.isToday && isButtonBeforeNow)}
27+
fill={isChosenButton ? 'horizontal' : false}
28+
justify="center"
29+
margin={{ top: 'xsmall' }}
30+
primary={isChosenButton}
31+
onClick={() => {
32+
props.onClick(props.frenchButtonValue);
33+
}}
34+
>
35+
<Box alignContent="center" alignSelf="center">
36+
<Text color="black" textAlign="center">
37+
{props.buttonValue}
38+
</Text>
39+
</Box>
40+
</Button>
41+
);
42+
};
43+
44+
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';

0 commit comments

Comments
 (0)