Skip to content

Commit eb4eebe

Browse files
devin-ai-integration[bot]somay@cal.comibex088
authored
feat: expose form validation methods from EventTypePlatformWrapper (calcom#22655)
* feat: expose form validation methods from EventTypePlatformWrapper - Add validateForm and handleFormSubmit methods to onFormStateChange prop - Update useEventTypeForm hook to return validateForm method - Add proper TypeScript types for form validation result - Enable external form validation and submission capabilities Co-Authored-By: somay@cal.com <somay@cal.com> * fix: correct forwardRef syntax to resolve parsing errors - Fix forwardRef parameter destructuring syntax - Use proper props parameter pattern for forwardRef components - Ensure prettier can parse the file correctly Co-Authored-By: somay@cal.com <somay@cal.com> * feat: add form validation and submission handlers to event types platform wrapper * refactor: move form validation and submit handlers from hook to wrapper component * fix: add ref to the save button for proper form validation * feat: extend ref-based validation API to AvailabilitySettingsPlatformWrapper - Add AvailabilityFormValidationResult and AvailabilitySettingsPlatformWrapperRef types - Implement forwardRef pattern in AvailabilitySettings component with save button ref - Add validateForm and handleFormSubmit methods using useImperativeHandle - Update AvailabilitySettingsPlatformWrapper to support ref forwarding - Add comprehensive documentation for ref-based validation API in both event-type.mdx and availability-settings.mdx - Follow same patterns established in EventTypePlatformWrapper for consistency Co-Authored-By: somay@cal.com <somay@cal.com> * refactor: rename AvailabilitySettingsPlatformWrapperRef to AvailabilitySettingsFormRef * feat: add ref-based validation pattern to availability example page - Mirror the ref-based validation implementation from event-types.tsx - Add useRef, handleValidate, and handleSubmit functions - Demonstrate validateForm() and handleFormSubmit() methods - Add validation and submit buttons to showcase the new API - Use AvailabilitySettingsFormRef type for proper typing Co-Authored-By: somay@cal.com <somay@cal.com> * refactor: remove unused state variables * docs: clarify form validation behavior for availability and event type atoms * chore: remove console.logs --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: somay@cal.com <somay@cal.com> Co-authored-by: Somay Chauhan <somaychauhan98@gmail.com>
1 parent 16a7bb7 commit eb4eebe

15 files changed

Lines changed: 749 additions & 449 deletions

File tree

docs/platform/atoms/availability-settings.mdx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,59 @@ Along with the props, Availability settings atom accepts custom styles via the *
133133
| overridesModalClassNames | Adds styling to the date overrides modal |
134134

135135
<Info>Please ensure all custom classnames are valid [Tailwind CSS](https://tailwindcss.com/) classnames.</Info>
136+
137+
## Programmatic Form Validation and Submission
138+
139+
The AvailabilitySettings component supports programmatic form validation and submission through a ref-based API. This allows you to validate availability data and submit forms programmatically without user interaction.
140+
141+
```js
142+
import { useRef } from 'react';
143+
import { AvailabilitySettings } from "@calcom/atoms";
144+
import type { AvailabilitySettingsFormRef } from "@calcom/atoms";
145+
146+
export function AvailabilityWithValidation() {
147+
const availabilityRef = useRef<AvailabilitySettingsFormRef>(null);
148+
149+
const handleValidate = async () => {
150+
const result = await availabilityRef.current?.validateForm();
151+
if (result?.isValid) {
152+
console.log("Availability form is valid");
153+
} else {
154+
console.log("Validation errors:", result?.errors);
155+
}
156+
};
157+
158+
const handleSubmit = () => {
159+
availabilityRef.current?.handleFormSubmit();
160+
};
161+
162+
return (
163+
<>
164+
<AvailabilitySettings
165+
ref={availabilityRef}
166+
onUpdateSuccess={() => {
167+
console.log("Updated schedule successfully");
168+
}}
169+
onFormStateChange={(formState) => {
170+
console.log("Form state changed:", formState);
171+
}}
172+
/>
173+
<button onClick={handleValidate}>Validate Form</button>
174+
<button onClick={handleSubmit}>Submit Form</button>
175+
</>
176+
);
177+
}
178+
```
179+
180+
### Ref Methods
181+
182+
| Method | Description |
183+
|:-------|:------------|
184+
| validateForm | Validates the current availability form state and returns a promise with validation results. |
185+
| handleFormSubmit | Programmatically submits the availability form, triggering the same validation and submission flow as clicking the save button. Unlike `validateForm`, this method will check required fields and prevent submission unless all required fields are set |
186+
187+
The `validateForm` method returns an `AvailabilityFormValidationResult` object with:
188+
- `isValid`: Boolean indicating if the form passed validation
189+
- `errors`: Object containing any validation errors found
190+
191+
**Note:** If a required field is not filled in, the `validateForm` method will not return any error. The validation focuses on the format and consistency of provided data rather than enforcing required field completion.

docs/platform/atoms/event-type.mdx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,60 @@ Along with the props, event type settings atom accepts custom styles via the **c
196196
Please ensure all custom classnames are valid [Tailwind CSS](https://tailwindcss.com/) classnames.
197197
</Info>
198198

199+
## Programmatic Form Validation and Submission
200+
201+
The EventTypeSettings component supports programmatic form validation and submission through a ref-based API. This allows you to validate form data and submit forms programmatically without user interaction.
202+
203+
```js
204+
import { useRef } from 'react';
205+
import { EventTypeSettings } from "@calcom/atoms";
206+
import type { EventTypePlatformWrapperRef } from "@calcom/atoms";
207+
208+
export function EventTypeWithValidation(eventTypeId: number) {
209+
const eventTypeRef = useRef<EventTypePlatformWrapperRef>(null);
210+
211+
const handleValidate = async () => {
212+
const result = await eventTypeRef.current?.validateForm();
213+
if (result?.isValid) {
214+
console.log("Form is valid");
215+
} else {
216+
console.log("Validation errors:", result?.errors);
217+
}
218+
};
219+
220+
const handleSubmit = () => {
221+
eventTypeRef.current?.handleFormSubmit();
222+
};
223+
224+
return (
225+
<>
226+
<EventTypeSettings
227+
ref={eventTypeRef}
228+
id={eventTypeId}
229+
onSuccess={(eventType) => {
230+
console.log("EventType updated successfully", eventType);
231+
}}
232+
/>
233+
<button onClick={handleValidate}>Validate Form</button>
234+
<button onClick={handleSubmit}>Submit Form</button>
235+
</>
236+
);
237+
}
238+
```
239+
240+
### Ref Methods
241+
242+
| Method | Description |
243+
|:-------|:------------|
244+
| validateForm | Validates the current event type form state and returns a promise with validation results. |
245+
| handleFormSubmit | Programmatically submits the event type form, triggering the same validation and submission flow as clicking the save button. Unlike `validateForm`, this method will check required fields and prevent submission unless all required fields are set |
246+
247+
The `validateForm` method returns an `EventTypeFormValidationResult` object with:
248+
- `isValid`: Boolean indicating if the form passed validation
249+
- `errors`: Object containing any validation errors found
250+
251+
**Note:** If a required field is not filled in, the `validateForm` method will not return any error. The validation focuses on the format and consistency of provided data rather than enforcing required field completion.
252+
199253
Following are the tabs that are available in the event type settings atom:
200254
201255
<p></p>

packages/features/eventtypes/components/EventType.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export type EventTypeComponentProps = EventTypeSetupProps & {
6464
tabName: (typeof tabs)[number];
6565
tabsNavigation: VerticalTabItemProps[];
6666
allowDelete?: boolean;
67+
saveButtonRef?: React.RefObject<HTMLButtonElement>;
6768
};
6869

6970
export const EventType = ({
@@ -82,6 +83,7 @@ export const EventType = ({
8283
handleSubmit,
8384
children,
8485
allowDelete = true,
86+
saveButtonRef,
8587
}: EventTypeComponentProps) => {
8688
const [animationParentRef] = useAutoAnimate<HTMLDivElement>();
8789

@@ -101,7 +103,8 @@ export const EventType = ({
101103
isDeleting={isDeleting}
102104
isPlatform={isPlatform}
103105
allowDelete={allowDelete}
104-
tabsNavigation={tabsNavigation}>
106+
tabsNavigation={tabsNavigation}
107+
saveButtonRef={saveButtonRef}>
105108
<Form form={formMethods} id="event-type-form" handleSubmit={handleSubmit}>
106109
<div ref={animationParentRef}>{tabMap[tabName]}</div>
107110
</Form>

packages/features/eventtypes/components/EventTypeLayout.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type Props = {
4747
isPlatform?: boolean;
4848
tabsNavigation: VerticalTabItemProps[];
4949
allowDelete?: boolean;
50+
saveButtonRef?: React.RefObject<HTMLButtonElement>;
5051
};
5152

5253
function EventTypeSingleLayout({
@@ -64,6 +65,7 @@ function EventTypeSingleLayout({
6465
isPlatform,
6566
tabsNavigation,
6667
allowDelete = true,
68+
saveButtonRef,
6769
}: Props) {
6870
const { t } = useLocale();
6971
const eventTypesLockedByOrg = eventType.team?.parent?.organizationSettings?.lockEventTypeCreationForUsers;
@@ -262,6 +264,7 @@ function EventTypeSingleLayout({
262264
</Dropdown>
263265
<div className="border-default border-l-2" />
264266
<Button
267+
ref={saveButtonRef}
265268
className="ml-4 lg:ml-0"
266269
type="submit"
267270
loading={isUpdateMutationLoading}

packages/features/eventtypes/lib/types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,13 @@ export type SelectClassNames = {
220220
label?: string;
221221
container?: string;
222222
};
223+
224+
export type FormValidationResult = {
225+
isValid: boolean;
226+
errors: Record<string, unknown>;
227+
};
228+
229+
export interface EventTypePlatformWrapperRef {
230+
validateForm: () => Promise<FormValidationResult>;
231+
handleFormSubmit: () => void;
232+
}

0 commit comments

Comments
 (0)