Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import {
Box,
Button,
ButtonGroup,
Field,
FieldLabel,
FieldRow,
FieldError,
TextInput,
TextAreaInput,
Select,
ToggleSwitch,
Modal,
ModalHeader,
ModalTitle,
ModalClose,
ModalContent,
ModalFooter
} from '@rocket.chat/fuselage';
import { useTranslation, useEndpoint, useToastMessageDispatch } from '@rocket.chat/ui-contexts';
import { useQueryClient } from '@tanstack/react-query';
import type { ReactElement } from 'react';
import React from 'react';
import { useForm, Controller } from 'react-hook-form';

type CreateEventModalProps = {
onClose: () => void;
};

type CreateEventFormValues = {
subject: string;
description?: string;
startTime: string;
endTime?: string;
meetingUrl?: string;
reminderMinutesBeforeStart?: string;
busy: boolean;
};
Comment on lines +26 to +38
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Form type has description as optional, but the API requires it.

According to CalendarEventCreateProps, description is in the required array alongside startTime and subject. The form type marks it optional (description?: string), which will lead to API validation failures when users submit without a description.

Proposed fix
 type CreateEventFormValues = {
 	subject: string;
-	description?: string;
+	description: string;
 	startTime: string;
 	endTime?: string;
 	meetingUrl?: string;
 	reminderMinutesBeforeStart?: string;
 	busy: boolean;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
type CreateEventModalProps = {
onClose: () => void;
};
type CreateEventFormValues = {
subject: string;
description?: string;
startTime: string;
endTime?: string;
meetingUrl?: string;
reminderMinutesBeforeStart?: string;
busy: boolean;
};
type CreateEventModalProps = {
onClose: () => void;
};
type CreateEventFormValues = {
subject: string;
description: string;
startTime: string;
endTime?: string;
meetingUrl?: string;
reminderMinutesBeforeStart?: string;
busy: boolean;
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/views/calendar/CreateEventModal/CreateEventModal.tsx`
around lines 26 - 38, The CreateEventFormValues type marks description optional
but the API (CalendarEventCreateProps) requires description; update the
CreateEventFormValues type so description is a required string (remove the ?),
and ensure any form initialization or validation logic that constructs
CreateEventFormValues (e.g., default values or formik/React Hook Form
initialValues) provides a non-empty description value and validation rule so
submissions include description.


const CreateEventModal = ({ onClose }: CreateEventModalProps): ReactElement => {
const t = useTranslation();
const dispatchToastMessage = useToastMessageDispatch();
const queryClient = useQueryClient();
const createEvent = useEndpoint('POST', '/v1/calendar-events.create');

const {
register,
handleSubmit,
control,
formState: { errors, isValid, isSubmitting },
} = useForm<CreateEventFormValues>({
mode: 'onChange',
defaultValues: {
busy: true,
reminderMinutesBeforeStart: '15',
},
});

const onSubmit = async (data: CreateEventFormValues) => {
try {
await createEvent({
subject: data.subject,
description: data.description || undefined,
startTime: new Date(data.startTime).toISOString(),
endTime: data.endTime ? new Date(data.endTime).toISOString() : undefined,
meetingUrl: data.meetingUrl || undefined,
reminderMinutesBeforeStart: data.reminderMinutesBeforeStart ? parseInt(data.reminderMinutesBeforeStart, 10) : undefined,
busy: data.busy,
});

dispatchToastMessage({ type: 'success', message: t('Event_Created_Successfully') });
queryClient.invalidateQueries({ queryKey: ['calendar', 'list'] });
onClose();
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
}
};
Comment on lines +59 to +77
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Two issues in the submit handler.

  1. Line 63: Sending undefined for description will fail API validation since description is required per the schema (required: ['startTime', 'subject', 'description']).

  2. Line 75: Passing the raw error object to dispatchToastMessage may not display correctly. The message property typically expects a string.

Proposed fix
 	const onSubmit = async (data: CreateEventFormValues) => {
 		try {
 			await createEvent({
 				subject: data.subject,
-				description: data.description || undefined,
+				description: data.description,
 				startTime: new Date(data.startTime).toISOString(),
 				endTime: data.endTime ? new Date(data.endTime).toISOString() : undefined,
 				meetingUrl: data.meetingUrl || undefined,
 				reminderMinutesBeforeStart: data.reminderMinutesBeforeStart ? parseInt(data.reminderMinutesBeforeStart, 10) : undefined,
 				busy: data.busy,
 			});

 			dispatchToastMessage({ type: 'success', message: t('Event_Created_Successfully') });
 			queryClient.invalidateQueries({ queryKey: ['calendar', 'list'] });
 			onClose();
 		} catch (error) {
-			dispatchToastMessage({ type: 'error', message: error });
+			dispatchToastMessage({ type: 'error', message: error instanceof Error ? error.message : t('Something_went_wrong') });
 		}
 	};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/views/calendar/CreateEventModal/CreateEventModal.tsx`
around lines 59 - 77, The submit handler onSubmit must send a valid description
and a string message on error: ensure you always provide description when
calling createEvent (e.g., use data.description ?? '' or validate/require it
before calling) so it doesn't send undefined (createEvent / API schema requires
description), and change the error toast to pass a string (e.g., error.message
or String(error)) to dispatchToastMessage so the message displays correctly;
update the createEvent call and the catch block in onSubmit accordingly.


const reminderOptions: [string, string][] = [
['0', t('At_time_of_event')],
['5', t('5_minutes_before')],
['10', t('10_minutes_before')],
['15', t('15_minutes_before')],
['30', t('30_minutes_before')],
['60', t('1_hour_before')],
];

return (
<Modal wrapperFunction={(wrapper) => <form onSubmit={handleSubmit(onSubmit)}>{wrapper}</form>}>
<ModalHeader>
<ModalTitle>{t('Create_Event')}</ModalTitle>
<ModalClose onClick={onClose} />
</ModalHeader>
<ModalContent>
<Field mbe={24}>
<FieldLabel required>{t('Subject')}</FieldLabel>
<FieldRow>
<TextInput
placeholder={t('Event_Subject')}
{...register('subject', { required: t('Field_required') })}
error={errors.subject?.message}
/>
</FieldRow>
{errors.subject && <FieldError>{errors.subject.message}</FieldError>}
</Field>

<Field mbe={24}>
<FieldLabel required>{t('Start_Time')}</FieldLabel>
<FieldRow>
<TextInput
type='datetime-local'
{...register('startTime', { required: t('Field_required') })}
error={errors.startTime?.message}
/>
</FieldRow>
{errors.startTime && <FieldError>{errors.startTime.message}</FieldError>}
</Field>

<Field mbe={24}>
<FieldLabel>{t('End_Time')}</FieldLabel>
<FieldRow>
<TextInput
type='datetime-local'
{...register('endTime')}
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: endTime is accepted without validating it is after startTime, allowing invalid event ranges to be submitted and stored.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/client/views/calendar/CreateEventModal/CreateEventModal.tsx, line 124:

<comment>`endTime` is accepted without validating it is after `startTime`, allowing invalid event ranges to be submitted and stored.</comment>

<file context>
@@ -0,0 +1,189 @@
+					<FieldRow>
+						<TextInput
+							type='datetime-local'
+							{...register('endTime')}
+						/>
+					</FieldRow>
</file context>
Fix with Cubic

/>
</FieldRow>
</Field>

<Field mbe={24}>
<FieldLabel>{t('Meeting_URL')}</FieldLabel>
<FieldRow>
<TextInput
type='url'
placeholder='https://...'
{...register('meetingUrl')}
/>
</FieldRow>
</Field>

<Field mbe={24}>
<FieldLabel>{t('Description')}</FieldLabel>
<FieldRow>
<TextAreaInput
rows={3}
{...register('description')}
/>
</FieldRow>
</Field>
Comment on lines +140 to +148
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Description field is missing required validation.

The API schema requires description as a mandatory field. The UI should mark this field as required and add validation to prevent form submission without it.

Proposed fix
 				<Field mbe={24}>
-					<FieldLabel>{t('Description')}</FieldLabel>
+					<FieldLabel required>{t('Description')}</FieldLabel>
 					<FieldRow>
 						<TextAreaInput
 							rows={3}
-							{...register('description')}
+							{...register('description', { required: t('Field_required') })}
+							error={errors.description?.message}
 						/>
 					</FieldRow>
+					{errors.description && <FieldError>{errors.description.message}</FieldError>}
 				</Field>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/views/calendar/CreateEventModal/CreateEventModal.tsx`
around lines 140 - 148, The Description textarea (registered as
register('description') inside CreateEventModal) is missing required validation
and a UI required indicator; update the FieldLabel to show required (e.g.,
append '*' or set a required prop) and add validation to the form registration
for 'description' (make it required with an appropriate message), then surface
validation errors near TextAreaInput (use the form's errors for 'description' to
show feedback and prevent submission when empty).


<Field mbe={24}>
<FieldLabel>{t('Reminder')}</FieldLabel>
<FieldRow>
<Controller
name='reminderMinutesBeforeStart'
control={control}
render={({ field }) => <Select {...field} options={reminderOptions} />}
/>
</FieldRow>
</Field>

<Field mbe={16}>
<Box display='flex' alignItems='center'>
<FieldLabel mbe={0}>{t('Show_as_busy')}</FieldLabel>
<Controller
name='busy'
control={control}
render={({ field }) => (
<ToggleSwitch
checked={field.value}
onChange={field.onChange}
/>
)}
/>
</Box>
</Field>
</ModalContent>
<ModalFooter>
<ButtonGroup align='end'>
<Button onClick={onClose}>{t('Cancel')}</Button>
<Button primary type='submit' loading={isSubmitting} disabled={!isValid}>
{t('Save')}
</Button>
</ButtonGroup>
</ModalFooter>
</Modal>
);
};

export default CreateEventModal;
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import {
ContextualbarContent,
ContextualbarFooter,
ContextualbarDialog,
imperativeModal,
} from '@rocket.chat/ui-client';
import { useTranslation, useUser } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import { Virtuoso } from 'react-virtuoso';

import OutlookEventItem from './OutlookEventItem';
import CreateEventModal from '../../calendar/CreateEventModal/CreateEventModal';
import { getErrorMessage } from '../../../lib/errorHandling';
import { useOutlookAuthentication } from '../hooks/useOutlookAuthentication';
import { useMutationOutlookCalendarSync, useOutlookCalendarListForToday } from '../hooks/useOutlookCalendarList';
Expand Down Expand Up @@ -86,6 +88,7 @@ const OutlookEventsList = ({ onClose, changeRoute }: OutlookEventsListProps): Re
</ContextualbarContent>
<ContextualbarFooter>
<ButtonGroup stretch>
{authEnabled && <Button onClick={() => imperativeModal.open({ component: CreateEventModal, props: { onClose: imperativeModal.close } })}>{t('Create_Event')}</Button>}
{authEnabled && <Button onClick={changeRoute}>{t('Calendar_settings')}</Button>}
{outlookUrl && (
<Button icon='new-window' onClick={() => window.open(outlookUrl, '_blank')}>
Expand Down