Skip to content

Commit d3fbc73

Browse files
feat: add callback for handleFormSubmit in EventType and AvailabilitySettings atoms (#22911)
* feat: Implement callback pattern in handleFormSubmit of EventTypePlatformWrapper * feat: Implement callback pattern in handleFormSubmit of AvailabilitySettingsPlatformWrapper * docs: add handleFormSubmit callback documentation for EventType and AvailabilitySettings atoms * Update availability.tsx * chore:added changelog * update docs --------- Co-authored-by: Rajiv Sahal <sahalrajiv-extc@atharvacoe.ac.in>
1 parent cfda475 commit d3fbc73

File tree

10 files changed

+129
-17
lines changed

10 files changed

+129
-17
lines changed

.changeset/forty-clubs-mate.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@calcom/atoms": minor
3+
---
4+
5+
Added new callback functions to the handleFormSubmit method in the EventTypeSettings and AvailabilitySettings atoms. The handleFormSubmit method now accepts an optional callbacks object with the following properties:
6+
7+
- **onSuccess**: Called when the form submission is successful, allowing additional logic to be executed after the update.
8+
9+
- **onError**: Called when an error occurs during form submission, providing details about the error to handle specific cases or display custom messages.

docs/platform/atoms/availability-settings.mdx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,16 @@ export function AvailabilityWithValidation() {
156156
};
157157

158158
const handleSubmit = () => {
159-
availabilityRef.current?.handleFormSubmit();
159+
availabilityRef.current?.handleFormSubmit({
160+
onSuccess: () => {
161+
// Additional success handling logic here
162+
console.log('Availability updated successfully');
163+
},
164+
onError: (error) => {
165+
// Additional error handling logic here
166+
console.error('Error updating availability:', error);
167+
}
168+
});
160169
};
161170

162171
return (
@@ -184,6 +193,20 @@ export function AvailabilityWithValidation() {
184193
| validateForm | Validates the current availability form state and returns a promise with validation results. |
185194
| 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 |
186195
196+
### Callbacks
197+
198+
The `handleFormSubmit` method accepts an optional callbacks object with the following properties:
199+
200+
```typescript
201+
type AvailabilitySettingsFormCallbacks = {
202+
onSuccess?: () => void;
203+
onError?: (error: Error) => void;
204+
};
205+
```
206+
207+
- **onSuccess**: Called when the form submission is successful. This allows you to execute additional logic after a successful update.
208+
- **onError**: Called when an error occurs during form submission. The error parameter contains details about what went wrong, allowing you to handle specific error cases or display custom error messages.
209+
187210
The `validateForm` method returns an `AvailabilityFormValidationResult` object with:
188211
- `isValid`: Boolean indicating if the form passed validation
189212
- `errors`: Object containing any validation errors found

docs/platform/atoms/event-type.mdx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,16 @@ export function EventTypeWithValidation(eventTypeId: number) {
218218
};
219219

220220
const handleSubmit = () => {
221-
eventTypeRef.current?.handleFormSubmit();
221+
eventTypeRef.current?.handleFormSubmit({
222+
onSuccess: () => {
223+
// Additional success handling logic here
224+
console.log('Event type updated successfully');
225+
},
226+
onError: (error) => {
227+
// Additional error handling logic here
228+
console.error('Error updating event type:', error);
229+
}
230+
});
222231
};
223232

224233
return (
@@ -244,6 +253,20 @@ export function EventTypeWithValidation(eventTypeId: number) {
244253
| validateForm | Validates the current event type form state and returns a promise with validation results. |
245254
| 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 |
246255
256+
### Callbacks
257+
258+
The `handleFormSubmit` method accepts an optional callbacks object with the following properties:
259+
260+
```typescript
261+
type EventTypeFormCallbacks = {
262+
onSuccess?: () => void;
263+
onError?: (error: Error) => void;
264+
};
265+
```
266+
267+
- **onSuccess**: Called when the form submission is successful. This allows you to execute additional logic after a successful update.
268+
- **onError**: Called when an error occurs during form submission. The error parameter contains details about what went wrong, allowing you to handle specific error cases or display custom error messages.
269+
247270
The `validateForm` method returns an `EventTypeFormValidationResult` object with:
248271
- `isValid`: Boolean indicating if the form passed validation
249272
- `errors`: Object containing any validation errors found

packages/features/eventtypes/lib/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,5 +236,5 @@ export type FormValidationResult = {
236236

237237
export interface EventTypePlatformWrapperRef {
238238
validateForm: () => Promise<FormValidationResult>;
239-
handleFormSubmit: () => void;
239+
handleFormSubmit: (callbacks?: { onSuccess?: () => void; onError?: (error: Error) => void }) => void;
240240
}

packages/platform/atoms/availability/AvailabilitySettings.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,11 +316,24 @@ export const AvailabilitySettings = forwardRef<AvailabilitySettingsFormRef, Avai
316316

317317
const saveButtonRef = useRef<HTMLButtonElement>(null);
318318

319-
const handleFormSubmit = useCallback(() => {
319+
const callbacksRef = useRef<{ onSuccess?: () => void; onError?: (error: Error) => void }>({});
320+
321+
const handleFormSubmit = useCallback((customCallbacks?: { onSuccess?: () => void; onError?: (error: Error) => void }) => {
322+
if (customCallbacks) {
323+
callbacksRef.current = customCallbacks;
324+
}
325+
320326
if (saveButtonRef.current) {
321327
saveButtonRef.current.click();
322328
} else {
323-
form.handleSubmit(handleSubmit)();
329+
form.handleSubmit(async (data) => {
330+
try {
331+
await handleSubmit(data);
332+
callbacksRef.current?.onSuccess?.();
333+
} catch (error) {
334+
callbacksRef.current?.onError?.(error as Error);
335+
}
336+
})();
324337
}
325338
}, [form, handleSubmit]);
326339

packages/platform/atoms/availability/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ export type AvailabilityFormValidationResult = {
3535
errors: Record<string, unknown>;
3636
};
3737

38+
export interface AvailabilitySettingsFormCallbacks {
39+
onSuccess?: () => void;
40+
onError?: (error: Error) => void;
41+
}
42+
3843
export interface AvailabilitySettingsFormRef {
3944
validateForm: () => Promise<AvailabilityFormValidationResult>;
40-
handleFormSubmit: () => void;
45+
handleFormSubmit: (callbacks?: AvailabilitySettingsFormCallbacks) => void;
4146
}

packages/platform/atoms/availability/wrappers/AvailabilitySettingsPlatformWrapper.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ReactNode } from "react";
2-
import { forwardRef } from "react";
2+
import { forwardRef, useRef } from "react";
33

44
import type { ScheduleLabelsType } from "@calcom/features/schedules/components/Schedule";
55
import type { UpdateScheduleResponse } from "@calcom/lib/schedules/updateSchedule";
@@ -12,9 +12,9 @@ import { useMe } from "../../hooks/useMe";
1212
import { AtomsWrapper } from "../../src/components/atoms-wrapper";
1313
import { useToast } from "../../src/components/ui/use-toast";
1414
import type { Availability } from "../AvailabilitySettings";
15-
import type { CustomClassNames, AvailabilitySettingsFormRef } from "../AvailabilitySettings";
15+
import type { CustomClassNames } from "../AvailabilitySettings";
1616
import { AvailabilitySettings } from "../AvailabilitySettings";
17-
import type { AvailabilityFormValues } from "../types";
17+
import type { AvailabilityFormValues, AvailabilitySettingsFormRef } from "../types";
1818

1919
export type AvailabilitySettingsPlatformWrapperProps = {
2020
id?: string;
@@ -39,7 +39,7 @@ export type AvailabilitySettingsPlatformWrapperProps = {
3939
};
4040

4141
export const AvailabilitySettingsPlatformWrapper = forwardRef<
42-
AvailabilitySettingsFormRef,
42+
AvailabilitySettingsFormRef,
4343
AvailabilitySettingsPlatformWrapperProps
4444
>(function AvailabilitySettingsPlatformWrapper(props, ref) {
4545
const {
@@ -84,6 +84,8 @@ export const AvailabilitySettingsPlatformWrapper = forwardRef<
8484
},
8585
});
8686

87+
const callbacksRef = useRef<{ onSuccess?: () => void; onError?: (error: Error) => void }>({});
88+
8789
const { mutate: updateSchedule, isPending: isSavingInProgress } = useAtomUpdateSchedule({
8890
onSuccess: (res) => {
8991
onUpdateSuccess?.(res);
@@ -92,6 +94,7 @@ export const AvailabilitySettingsPlatformWrapper = forwardRef<
9294
description: "Schedule updated successfully",
9395
});
9496
}
97+
callbacksRef.current?.onSuccess?.();
9598
},
9699
onError: (err) => {
97100
onUpdateError?.(err);
@@ -100,6 +103,7 @@ export const AvailabilitySettingsPlatformWrapper = forwardRef<
100103
description: "Could not update schedule",
101104
});
102105
}
106+
callbacksRef.current?.onError?.(err);
103107
},
104108
});
105109

packages/platform/atoms/event-types/wrappers/EventTypePlatformWrapper.tsx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,20 @@ const EventType = forwardRef<
139139
form.reset(currentValues);
140140
toast({ description: t("event_type_updated_successfully", { eventTypeTitle: eventType.title }) });
141141
onSuccess?.(currentValues);
142+
callbacksRef.current?.onSuccess?.();
142143
},
143144
async onSettled() {
144145
return;
145146
},
146147
onError: (err: Error) => {
147148
const currentValues = form.getValues();
148149
const message = err?.message;
149-
toast({ description: message ? t(message) : t(err.message) });
150+
const description = message ? t(message) : t(err.message);
151+
toast({ description });
150152
onError?.(currentValues, err);
153+
154+
const errorObj = new Error(description);
155+
callbacksRef.current?.onError?.(errorObj);
151156
},
152157
teamId: team?.id,
153158
});
@@ -159,6 +164,7 @@ const EventType = forwardRef<
159164
updateMutation.mutate(data);
160165
} else {
161166
toast({ description: t("event_type_updated_successfully", { eventTypeTitle: eventType.title }) });
167+
callbacksRef.current?.onSuccess?.();
162168
}
163169
},
164170
onFormStateChange: onFormStateChange,
@@ -167,11 +173,24 @@ const EventType = forwardRef<
167173
// Create a ref for the save button to trigger its click
168174
const saveButtonRef = useRef<HTMLButtonElement>(null);
169175

170-
const handleFormSubmit = useCallback(() => {
176+
const callbacksRef = useRef<{ onSuccess?: () => void; onError?: (error: Error) => void }>({});
177+
178+
const handleFormSubmit = useCallback((customCallbacks?: { onSuccess?: () => void; onError?: (error: Error) => void }) => {
179+
if (customCallbacks) {
180+
callbacksRef.current = customCallbacks;
181+
}
182+
171183
if (saveButtonRef.current) {
172184
saveButtonRef.current.click();
173185
} else {
174-
form.handleSubmit(handleSubmit)();
186+
form.handleSubmit((data) => {
187+
try {
188+
handleSubmit(data);
189+
customCallbacks?.onSuccess?.();
190+
} catch (error) {
191+
customCallbacks?.onError?.(error as Error);
192+
}
193+
})();
175194
}
176195
}, [handleSubmit, form]);
177196

packages/platform/examples/base/src/pages/availability.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Navbar } from "@/components/Navbar";
22
import { Inter } from "next/font/google";
3-
import { useRef, useCallback } from "react";
3+
import { useRef, useCallback, useState } from "react";
44

55
import type { AvailabilitySettingsFormRef } from "@calcom/atoms";
66
import { AvailabilitySettings } from "@calcom/atoms";
@@ -20,7 +20,14 @@ export default function Availability(props: { calUsername: string; calEmail: str
2020
};
2121

2222
const handleSubmit = () => {
23-
availabilityRef.current?.handleFormSubmit();
23+
availabilityRef.current?.handleFormSubmit({
24+
onSuccess: () => {
25+
console.log("Form submitted successfully");
26+
},
27+
onError: (error) => {
28+
console.error("Form submission failed:", error);
29+
},
30+
});
2431
};
2532

2633
return (
@@ -29,7 +36,7 @@ export default function Availability(props: { calUsername: string; calEmail: str
2936
<div>
3037
<h1 className="mx-10 my-4 text-2xl font-semibold">Availability Settings</h1>
3138

32-
<div className="mx-10 mb-4 flex gap-4">
39+
<div className="mx-10 mb-4 flex flex-col gap-4">
3340
<button
3441
onClick={handleValidate}
3542
className="rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50">

packages/platform/examples/base/src/pages/event-types.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,16 @@ export default function Bookings(props: { calUsername: string; calEmail: string
3131
};
3232

3333
const handleSubmit = () => {
34-
eventTypeRef.current?.handleFormSubmit();
34+
eventTypeRef.current?.handleFormSubmit({
35+
onSuccess: () => {
36+
console.log('Event type updated successfully');
37+
// Additional success handling logic here
38+
},
39+
onError: (error) => {
40+
console.error('Error updating event type:', error);
41+
// Additional error handling logic here
42+
}
43+
});
3544
};
3645
const { isLoading: isLoadingEvents, data: eventTypes, refetch } = useEventTypes(props.calUsername);
3746
const { data: teams } = useTeams();

0 commit comments

Comments
 (0)