From a0b0062477528584c88cb6d28f3b634732ab8c56 Mon Sep 17 00:00:00 2001 From: karabij Date: Fri, 2 Dec 2022 17:22:16 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20add=20meeting=20register?= =?UTF-8?q?=20form?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add a form which enables the user to register the meeting --- src/frontend/magnify/package.json | 2 + .../FormikDatePicker.stories.tsx | 24 -- .../FormikDatePicker/FormikDatePicker.tsx | 102 -------- .../Formik/FormikDatePicker/index.ts | 1 - .../FormikDateTimePicker.stories.tsx | 30 +++ .../FormikDateTimePicker.tsx | 152 ++++++++++++ .../FormikDateTimePicker/SuggestionButton.tsx | 44 ++++ .../Formik/FormikDateTimePicker/index.ts | 1 + .../Formik/FormikDateTimePicker/utils.tsx | 31 +++ .../FormikTimePicker.stories.tsx | 24 -- .../FormikTimePicker/FormikTimePicker.tsx | 142 ----------- .../Formik/FormikTimePicker/index.ts | 1 - .../Formik/Select/MeetingRecurrence/index.tsx | 69 ++++++ .../meetings/MyMeetings/MyMeetings.tsx | 4 + .../RegisterMeeting.stories.tsx | 13 ++ .../RegisterMeeting/RegisterMeeting.tsx | 69 ++++++ .../RegisterMeetingForm.stories.tsx | 18 ++ .../RegisterMeetingForm.tsx | 147 ++++++++++++ .../meetings/RegisterMeetingForm/index.tsx | 1 + .../meetings/RegisterMeetingForm/utils.tsx | 221 ++++++++++++++++++ src/frontend/magnify/src/services/index.ts | 1 + .../magnify/src/services/meetings/index.ts | 1 + .../services/meetings/meetings.repository.ts | 57 +++++ src/frontend/magnify/src/types/api/index.ts | 1 + .../magnify/src/types/api/meeting/index.ts | 7 + .../src/utils/constants/react-query/index.ts | 2 + .../magnify/src/utils/routes/api/index.ts | 1 + .../src/utils/routes/api/meetings/index.ts | 7 + src/frontend/package-lock.json | 94 +++++++- src/frontend/yarn.lock | 42 +++- 30 files changed, 1011 insertions(+), 298 deletions(-) delete mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/FormikDatePicker.stories.tsx delete mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/FormikDatePicker.tsx delete mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/index.ts create mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/FormikDateTimePicker.stories.tsx create mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/FormikDateTimePicker.tsx create mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/SuggestionButton.tsx create mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/index.ts create mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/utils.tsx delete mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/FormikTimePicker.stories.tsx delete mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/FormikTimePicker.tsx delete mode 100644 src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/index.ts create mode 100644 src/frontend/magnify/src/components/design-system/Formik/Select/MeetingRecurrence/index.tsx create mode 100644 src/frontend/magnify/src/components/meetings/RegisterMeeting/RegisterMeeting.stories.tsx create mode 100644 src/frontend/magnify/src/components/meetings/RegisterMeetingForm/RegisterMeetingForm.stories.tsx create mode 100644 src/frontend/magnify/src/components/meetings/RegisterMeetingForm/RegisterMeetingForm.tsx create mode 100644 src/frontend/magnify/src/components/meetings/RegisterMeetingForm/index.tsx create mode 100644 src/frontend/magnify/src/components/meetings/RegisterMeetingForm/utils.tsx create mode 100644 src/frontend/magnify/src/services/meetings/index.ts create mode 100644 src/frontend/magnify/src/services/meetings/meetings.repository.ts create mode 100644 src/frontend/magnify/src/types/api/meeting/index.ts create mode 100644 src/frontend/magnify/src/utils/routes/api/meetings/index.ts diff --git a/src/frontend/magnify/package.json b/src/frontend/magnify/package.json index 48f438398..bb84e9dcb 100644 --- a/src/frontend/magnify/package.json +++ b/src/frontend/magnify/package.json @@ -36,6 +36,7 @@ "@testing-library/react": "13.3.0", "@testing-library/user-event": "14.2.1", "@types/jest": "28.1.1", + "@types/luxon": "^3.1.0", "@types/react": "18.0.12", "@types/react-time-picker": "^4.0.2", "@types/styled-components": "5.1.25", @@ -57,6 +58,7 @@ "jest": "28.1.1", "jest-css-modules": "2.1.0", "jest-environment-jsdom": "28.1.1", + "luxon": "^3.1.1", "msw": "0.47.4", "postcss": "8.4.14", "prettier": "2.7.0", diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/FormikDatePicker.stories.tsx b/src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/FormikDatePicker.stories.tsx deleted file mode 100644 index 93041f703..000000000 --- a/src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/FormikDatePicker.stories.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import withFormik from '@bbbtech/storybook-formik'; -import { ComponentMeta, ComponentStory } from '@storybook/react'; -import React from 'react'; -import FormikDatePicker from './FormikDatePicker'; - -export default { - title: 'Formik/DatePicker', - component: FormikDatePicker, - decorators: [withFormik], - initialValues: { date: new Date() }, -} as ComponentMeta; - -const Template: ComponentStory = (args, context) => ( -
- {context.parameters.title} - -
-); - -export const basicDatePicker = Template.bind({}); - -basicDatePicker.args = { - name: 'date', -}; diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/FormikDatePicker.tsx b/src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/FormikDatePicker.tsx deleted file mode 100644 index 8c61ec7a7..000000000 --- a/src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/FormikDatePicker.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { useField, useFormikContext } from 'formik'; -import { DateInput, Box, Text, ThemeContext, ThemeType } from 'grommet'; -import { Alert } from 'grommet-icons'; -import { normalizeColor } from 'grommet/utils'; -import React, { useState, FunctionComponent } from 'react'; -import { defineMessages, useIntl } from 'react-intl'; -import { useTheme } from 'styled-components'; - -const messages = defineMessages({ - invalidStartingAt: { - defaultMessage: 'Input date is not valid: Starting date should be set in the future.', - description: 'Error message when event scheduling date time update is in the past.', - id: 'components.design-system.Formik.FormikDatePicker.invalidStartingAt', - }, -}); - -const customDateInputTheme = (theme: ThemeType) => { - return { - dateInput: { - container: { - background: normalizeColor('light-2', theme), - round: 'medium', - }, - }, - calendar: { - day: { extend: () => `border-radius: 2em; color: brand` }, - extend: `border-radius: 1em; padding: 1em`, - }, - maskedInput: { - extend: `font-family: roboto`, - }, - }; -}; - -export interface formikDatePickerProps { - name: string; - onChange: (date: string) => void; -} - -const nextYear = new Date(); -nextYear.setFullYear(new Date().getFullYear() + 1); -const today = new Date(); -today.setHours(0, 0, 0, 0); - -const FormikDatePicker: FunctionComponent = ({ ...props }) => { - const [field] = useField(props.name); - const [startingAtError, setStartingAtError] = useState(false); - - const formikContext = useFormikContext(); - const intl = useIntl(); - - const theme = useTheme(); - const onDateChange = (event: { value: string | string[] }) => { - setStartingAtError(false); - let value: string; - if (Array.isArray(event.value)) { - value = ''; - if (event.value.length > 0) { - value = event.value[0]; - } - } else { - value = event.value; - } - setStartingAtError(value != '' && value < today.toISOString()); - formikContext.setFieldValue(props.name, value); - }; - - return ( - - - - {startingAtError && ( - - - - {intl.formatMessage(messages.invalidStartingAt)} - - - )} - - - ); -}; - -export default FormikDatePicker; diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/index.ts b/src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/index.ts deleted file mode 100644 index 8d04f8044..000000000 --- a/src/frontend/magnify/src/components/design-system/Formik/FormikDatePicker/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default, formikDatePickerProps } from './FormikDatePicker'; diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/FormikDateTimePicker.stories.tsx b/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/FormikDateTimePicker.stories.tsx new file mode 100644 index 000000000..a9d63022f --- /dev/null +++ b/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/FormikDateTimePicker.stories.tsx @@ -0,0 +1,30 @@ +import withFormik from '@bbbtech/storybook-formik'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import React from 'react'; +import { useIntl } from 'react-intl'; +import { getSuggestions } from '../../../meetings/RegisterMeetingForm/utils'; +import FormikDateTimePicker from './FormikDateTimePicker'; + +export default { + title: 'Formik/DateTimePicker', + component: FormikDateTimePicker, + decorators: [withFormik], + initialValues: { date: new Date() }, +} as ComponentMeta; + +const Template: ComponentStory = (args, context) => ( +
+ {context.parameters.title} + +
+); + +export const basicDateTimePicker = Template.bind({}); +const intl = useIntl(); + +basicDateTimePicker.args = { + timeName: 'time', + dateName: 'date', + frenchSuggestions: getSuggestions('fr'), + localTimeSuggestions: getSuggestions(intl.locale), +}; diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/FormikDateTimePicker.tsx b/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/FormikDateTimePicker.tsx new file mode 100644 index 000000000..b83086256 --- /dev/null +++ b/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/FormikDateTimePicker.tsx @@ -0,0 +1,152 @@ +import { ErrorMessage, useField, useFormikContext } from 'formik'; +import { DateInput, DropButton, Box, Text } from 'grommet'; +import { DateTime, Settings } from 'luxon'; +import React, { FunctionComponent, useState } from 'react'; +import { defineMessages, useIntl } from 'react-intl'; +import TimePicker, { TimePickerValue } from 'react-time-picker'; +import SuggestionButton from './SuggestionButton'; +import { mergeDateTime } from './utils'; + +const messages = defineMessages({ + invalidTime: { + defaultMessage: 'Input time is not valid: Starting time should be set in the future.', + description: 'Error message when event scheduling date time update is in the past.', + id: 'components.design-system.Formik.FormikDateTimePicker.invalidTime', + }, +}); + +export interface formikDateTimePickerProps { + dateName: string; + timeName: string; + frenchSuggestions: string[]; + localTimeSuggestions: string[]; +} + +const nextYear = new Date(); +nextYear.setFullYear(new Date().getFullYear() + 1); + +const FormikDateTimePicker: FunctionComponent = ({ ...props }) => { + const [open, setOpen] = useState(undefined); + const [dateField] = useField(props.dateName); + const [timeField] = useField(props.timeName); + const [timeError, setTimeError] = useState(false); + + const formikContext = useFormikContext(); + const intl = useIntl(); + Settings.defaultLocale = intl.locale; + + const isToday = + DateTime.fromISO(dateField.value).toFormat('MM-dd-yyyy') == + DateTime.now().toFormat('MM-dd-yyyy'); + const beforeToday = + DateTime.fromISO(dateField.value).toFormat('MM-dd-yyyy') < + DateTime.now().toFormat('MM-dd-yyyy'); + + const onDateChange = (event: { value: string | string[] }) => { + let value: string; + if (Array.isArray(event.value)) { + value = ''; + if (event.value.length > 0) { + value = event.value[0]; + } + } else { + value = event.value; + } + formikContext.setFieldValue(props.dateName, value); + }; + + const onTimeChange = (value: TimePickerValue | string) => { + formikContext.setFieldValue(props.timeName, value.toString()); + console.log(formikContext.errors, formikContext.values); + }; + + const determineIfTimeError = () => { + const chosenDateTime = mergeDateTime(dateField.value, timeField.value); + if ( + timeField.value == undefined + ? new Date(dateField.value).setHours(0, 0, 0, 0) < new Date().setHours(0, 0, 0, 0) + : timeField.value == null + ? true + : chosenDateTime + ? chosenDateTime < DateTime.local().toISO() + : false + ) { + console.log('coucou'); + formikContext.setFieldError(props.timeName, 'nein !!'); + } + }; + + const onTimeSelectChange = (value: string) => { + onTimeChange(value); + setOpen(false); + }; + + React.useEffect(() => { + determineIfTimeError(); + console.log(`date: ${dateField.value}`); + console.log(`time:${timeField.value}`); + console.log(`dateTime: ${mergeDateTime(dateField.value, timeField.value)}`); + console.log(formikContext); + }, [dateField.value, timeField.value]); + + const suggestionButtons = props.localTimeSuggestions.map((value: string, index: number) => ( + + )); + + return ( + + + + setOpen(false)} + open={open} + dropContent={ + + {suggestionButtons} + + } + onOpen={() => { + setOpen(true); + }} + > + + + + { + return ( + + {msg} + + ); + }} + > + + ); +}; + +export default FormikDateTimePicker; diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/SuggestionButton.tsx b/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/SuggestionButton.tsx new file mode 100644 index 000000000..4754b41a8 --- /dev/null +++ b/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/SuggestionButton.tsx @@ -0,0 +1,44 @@ +import { Box, Button, Text } from 'grommet'; +import { normalizeColor } from 'grommet/utils'; +import React, { FunctionComponent, ReactElement } from 'react'; +import { useTheme } from 'styled-components'; +import { mergeDateTime } from './utils'; + +const today = new Date().toISOString(); + +export interface suggestionButtonProps { + buttonValue: string; + frenchButtonValue: string; + choiceValue: string; + onClick: (value: string) => void; + isToday: boolean; + beforeToday: boolean; +} + +const SuggestionButton: FunctionComponent = ({ ...props }): ReactElement => { + const isChosenButton: boolean = props.buttonValue == props.choiceValue; + const chosenDateTime = mergeDateTime(today, props.buttonValue); + const isButtonBeforeNow: boolean = chosenDateTime ? chosenDateTime < today : false; + const theme = useTheme(); + return ( + + ); +}; + +export default SuggestionButton; diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/index.ts b/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/index.ts new file mode 100644 index 000000000..d91c9912d --- /dev/null +++ b/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/index.ts @@ -0,0 +1 @@ +export { default, formikDateTimePickerProps } from '../FormikDateTimePicker/FormikDateTimePicker'; diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/utils.tsx b/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/utils.tsx new file mode 100644 index 000000000..80ce64964 --- /dev/null +++ b/src/frontend/magnify/src/components/design-system/Formik/FormikDateTimePicker/utils.tsx @@ -0,0 +1,31 @@ +import { DateTime, Duration } from 'luxon'; + +export const splitDateTime = (dateTimeISO: string | null): { date: string; time: string } => { + if (!dateTimeISO) { + return { date: '', time: '' }; + } + const dateTime = DateTime.fromISO(dateTimeISO); + return { + date: dateTime.toISODate(), + time: dateTime.toLocaleString(DateTime.TIME_24_SIMPLE), + }; +}; + +export const mergeDateTime = ( + dateString: string | null, + timeString: string | null, +): string | null => { + if (!dateString || !timeString) { + return null; + } + try { + const time = Duration.fromISOTime(timeString); + const dateTime = DateTime.fromISO(dateString).set({ + hour: time.hours, + minute: time.minutes, + }); + return dateTime.toISO(); + } catch (e) { + return null; + } +}; diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/FormikTimePicker.stories.tsx b/src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/FormikTimePicker.stories.tsx deleted file mode 100644 index 7078b42d3..000000000 --- a/src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/FormikTimePicker.stories.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import withFormik from '@bbbtech/storybook-formik'; -import { ComponentMeta, ComponentStory } from '@storybook/react'; -import React from 'react'; -import FormikTimePicker from './FormikTimePicker'; - -export default { - title: 'Formik/TimePicker', - component: FormikTimePicker, - decorators: [withFormik], -} as ComponentMeta; - -const Template: ComponentStory = (args, context) => ( -
- {context.parameters.title} - -
-); - -export const basicTimePicker = Template.bind({}); - -basicTimePicker.args = { - name: 'time', - isToday: true, -}; diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/FormikTimePicker.tsx b/src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/FormikTimePicker.tsx deleted file mode 100644 index b9f5794d4..000000000 --- a/src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/FormikTimePicker.tsx +++ /dev/null @@ -1,142 +0,0 @@ -/* eslint-disable react/no-unknown-property */ -import { useField, useFormikContext } from 'formik'; -import { Box, DropButton, Button, Text } from 'grommet'; -import { Alert } from 'grommet-icons'; -import { normalizeColor } from 'grommet/utils'; -import React, { FunctionComponent, ReactElement, useState } from 'react'; -import { defineMessages, useIntl } from 'react-intl'; -import TimePicker, { TimePickerValue } from 'react-time-picker'; -import { useTheme } from 'styled-components'; - -const messages = defineMessages({ - invalidTime: { - defaultMessage: 'Input time is not valid: it should be set in the future.', - description: 'Error message when event scheduling time update is in the past.', - id: 'components.design-system.Formik.FormikTimePicker.invalidTime', - }, -}); - -export interface FormikTimePickerProps { - name: string; - isToday: boolean; - onChange: (event: React.ChangeEvent) => void; -} - -const computeSuggestions = (): string[] => { - let suggestions = ['00:00']; - let minutes: string = '00'; - let hours: string = '00'; - - while (`${hours}:${minutes}` < '23:45') { - console.log(`${hours}:${minutes}`); - if (minutes == '45') { - hours = +hours >= 9 ? (+hours + 1).toString() : `0${(+hours + 1).toString()}`; - minutes = '00'; - } else { - minutes = (+minutes + 15).toString(); - } - suggestions.push(`${hours}:${minutes}`); - } - return suggestions; -}; - -const allSuggestions = computeSuggestions(); - -interface suggestionButtonProps { - buttonValue: string; - choiceValue: string; - onClick: (value: string) => void; -} - -const SuggestionButton: FunctionComponent = ({ ...props }): ReactElement => { - const isChosenButton: boolean = props.buttonValue == props.choiceValue; - const theme = useTheme(); - return ( - - ); -}; - -const FormikTimePicker: FunctionComponent = ({ ...props }) => { - const [field] = useField(props.name); - const formikContext = useFormikContext(); - const [open, setOpen] = useState(undefined); - const [timeError, setTimeError] = useState(false); - const intl = useIntl(); - - const onTimeChange = (value: TimePickerValue | string) => { - const today = new Date(); - if (props.isToday && value < `${today.getHours()}:${today.getMinutes()}`) { - setTimeError(true); - } else { - setTimeError(false); - formikContext.setFieldValue(props.name, value); - } - }; - - const onTimeSelectChange = (value: string) => { - onTimeChange(value); - setOpen(false); - }; - - const suggestionButtons = allSuggestions.map((value: string) => ( - - )); - - return ( - - setOpen(false)} - open={open} - dropContent={ - - {suggestionButtons} - - } - onOpen={() => { - setOpen(true); - }} - > - - - {timeError && ( - - - - {intl.formatMessage(messages.invalidTime)} - - - )} - - ); -}; - -export default FormikTimePicker; diff --git a/src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/index.ts b/src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/index.ts deleted file mode 100644 index b25c3106a..000000000 --- a/src/frontend/magnify/src/components/design-system/Formik/FormikTimePicker/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default, FormikTimePickerProps } from './FormikTimePicker'; diff --git a/src/frontend/magnify/src/components/design-system/Formik/Select/MeetingRecurrence/index.tsx b/src/frontend/magnify/src/components/design-system/Formik/Select/MeetingRecurrence/index.tsx new file mode 100644 index 000000000..8685c03cc --- /dev/null +++ b/src/frontend/magnify/src/components/design-system/Formik/Select/MeetingRecurrence/index.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { defineMessages, useIntl } from 'react-intl'; +import { FormikSelect } from '../index'; + +type recurrence = 'daily' | 'weekly' | 'monthly' | 'yearly'; + +interface MeetingRecurrenceSelectOption { + value?: recurrence; + label: string; +} + +const messages = defineMessages({ + noRecurrence: { + defaultMessage: "Doesn't repeat itself", + description: 'Define a non-recurrent meeting', + id: 'components.design-system.Formik.Select.MeetingRecurrence.noRecurrence', + }, + dailyRecurrence: { + defaultMessage: 'Every day of the week', + description: 'Define a daily meeting', + id: 'components.design-system.Formik.Select.MeetingRecurrence.dailyRecurrence', + }, + weeklyRecurrence: { + defaultMessage: 'Every week', + description: 'Define a weekly meeting', + id: 'components.design-system.Formik.Select.MeetingRecurrence.weekyRecurrence', + }, + monthlyRecurrence: { + defaultMessage: 'Every month', + description: 'Define a montlhy meeting', + id: 'components.design-system.Formik.Select.MeetingRecurrence.monthlyRecurrence', + }, + yearlyRecurrence: { + defaultMessage: 'Every year', + description: 'Define a yearly meeting', + id: 'components.design-system.Formik.Select.MeetingRecurrence.yearlyRecurrence', + }, +}); + +export interface FormikSelectMeetingRecurrenceProps { + changeCallback: (recurrence: string) => void; +} + +function FormikSelectLanguage({ ...props }: FormikSelectMeetingRecurrenceProps) { + const intl = useIntl(); + + const getAllOptions = (): MeetingRecurrenceSelectOption[] => { + return [ + { value: undefined, label: intl.formatMessage(messages.noRecurrence) }, + { value: 'daily', label: intl.formatMessage(messages.dailyRecurrence) }, + { value: 'weekly', label: intl.formatMessage(messages.weeklyRecurrence) }, + { value: 'monthly', label: intl.formatMessage(messages.monthlyRecurrence) }, + { value: 'yearly', label: intl.formatMessage(messages.yearlyRecurrence) }, + ]; + }; + + return ( + + ); +} + +export default FormikSelectLanguage; diff --git a/src/frontend/magnify/src/components/meetings/MyMeetings/MyMeetings.tsx b/src/frontend/magnify/src/components/meetings/MyMeetings/MyMeetings.tsx index 555f36cad..5e101c152 100644 --- a/src/frontend/magnify/src/components/meetings/MyMeetings/MyMeetings.tsx +++ b/src/frontend/magnify/src/components/meetings/MyMeetings/MyMeetings.tsx @@ -5,6 +5,7 @@ import { defineMessages } from 'react-intl'; import { useTranslations } from '../../../i18n'; import { Meeting } from '../../../types/entities/meeting'; import MeetingRow from '../MeetingRow'; +import RegisterMeeting from '../RegisterMeeting/RegisterMeeting'; const messages = defineMessages({ myMeetingsCardTitle: { @@ -32,6 +33,9 @@ const MyMeetings = ({ meetings = [] }: MyMeetingsProps) => { {intl.formatMessage(messages.myMeetingsCardTitle)} {meetings?.length > 0 ? ` (${meetings?.length})` : ''} +
+ +
{meetings?.length > 0 ? ( meetings.map((meeting) => { diff --git a/src/frontend/magnify/src/components/meetings/RegisterMeeting/RegisterMeeting.stories.tsx b/src/frontend/magnify/src/components/meetings/RegisterMeeting/RegisterMeeting.stories.tsx new file mode 100644 index 000000000..82b9837ed --- /dev/null +++ b/src/frontend/magnify/src/components/meetings/RegisterMeeting/RegisterMeeting.stories.tsx @@ -0,0 +1,13 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import React from 'react'; +import RegisterMeeting from './RegisterMeeting'; + +export default { + title: 'Meetings/RegisterMeeting', + component: RegisterMeeting, +} as ComponentMeta; + +const Template: ComponentStory = () => ; + +// create the template and stories +export const basicRegisterMeeting = Template.bind({}); diff --git a/src/frontend/magnify/src/components/meetings/RegisterMeeting/RegisterMeeting.tsx b/src/frontend/magnify/src/components/meetings/RegisterMeeting/RegisterMeeting.tsx index e69de29bb..fe9994e99 100644 --- a/src/frontend/magnify/src/components/meetings/RegisterMeeting/RegisterMeeting.tsx +++ b/src/frontend/magnify/src/components/meetings/RegisterMeeting/RegisterMeeting.tsx @@ -0,0 +1,69 @@ +import { Box, Button, Layer } from 'grommet'; +import { Add } from 'grommet-icons'; +import React, { useState } from 'react'; +import { defineMessages, useIntl } from 'react-intl'; + +import { Meeting } from '../../../types/entities/meeting'; +import RegisterMeetingForm from '../RegisterMeetingForm'; + +const messages = defineMessages({ + registerNewMeetingLabel: { + id: 'components.meetings.registerMeeting.registerNewMeetingLabel', + defaultMessage: 'Register new meeting', + description: 'Label for the button to register a new meeting', + }, + addNewMeetingLabel: { + id: 'components.meetings.registerMeeting.addNewMeetingLabel', + defaultMessage: 'Meeting', + description: 'Label for the button to register a new meeting', + }, +}); + +export interface RegisterMeetingProps { + onAddMeeting?: (meeting: Meeting) => void; +} + +const RegisterMeeting = ({ ...props }: RegisterMeetingProps) => { + const intl = useIntl(); + const [open, setOpen] = useState(false); + + const handleOpen = (event: React.MouseEvent) => { + event.preventDefault(); + setOpen(true); + }; + + const handleClose = (event?: React.MouseEvent | React.KeyboardEvent) => { + event?.preventDefault(); + setOpen(false); + }; + + const onAddSuccess = (meeting?: Meeting): void => { + handleClose(); + }; + + return ( + <> +