mirror of
https://github.com/hanzoai/calendar.git
synced 2026-10-30 14:46:43 +00:00
* refactor: move feature-flags, calendars, and schedules components from packages/features to apps/web/modules Co-Authored-By: [email protected] <[email protected]> * fix * fix * fix * fix: move DatePicker and DateOverrideInputDialog to apps/web/modules and update imports Co-Authored-By: [email protected] <[email protected]> * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * rename * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * wip * wip * wip * fix unit tests --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
211 lines
6.4 KiB
TypeScript
211 lines
6.4 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import { forwardRef, useRef } from "react";
|
|
|
|
import type { ScheduleLabelsType } from "@calcom/features/schedules/components/ScheduleComponent";
|
|
import type { UpdateScheduleResponse } from "@calcom/features/schedules/services/ScheduleService";
|
|
import type { ApiErrorResponse, ApiResponse, UpdateScheduleInput_2024_06_11 } from "@calcom/platform-types";
|
|
|
|
import { useAtomSchedule } from "../../hooks/schedules/useAtomSchedule";
|
|
import { useAtomUpdateSchedule } from "../../hooks/schedules/useAtomUpdateSchedule";
|
|
import useDeleteSchedule from "../../hooks/schedules/useDeleteSchedule";
|
|
import { useMe } from "../../hooks/useMe";
|
|
import { AtomsWrapper } from "../../src/components/atoms-wrapper";
|
|
import { useToast } from "../../src/components/ui/use-toast";
|
|
import type { Availability } from "../AvailabilitySettings";
|
|
import type { CustomClassNames } from "../AvailabilitySettings";
|
|
import { AvailabilitySettings } from "../AvailabilitySettings";
|
|
import type { AvailabilityFormValues, AvailabilitySettingsFormRef } from "../types";
|
|
|
|
export type AvailabilitySettingsPlatformWrapperProps = {
|
|
id?: string;
|
|
labels?: {
|
|
tooltips: Partial<ScheduleLabelsType>;
|
|
};
|
|
customClassNames?: Partial<CustomClassNames>;
|
|
onUpdateSuccess?: (res: ApiResponse<UpdateScheduleResponse>) => void;
|
|
onUpdateError?: (err: ApiErrorResponse) => void;
|
|
onDeleteSuccess?: (res: ApiResponse) => void;
|
|
onDeleteError?: (err: ApiErrorResponse) => void;
|
|
disableEditableHeading?: boolean;
|
|
enableOverrides?: boolean;
|
|
onBeforeUpdate?: (updateBody: UpdateScheduleInput_2024_06_11) => boolean | Promise<boolean>;
|
|
onFormStateChange?: (formState: AvailabilityFormValues) => void;
|
|
allowDelete?: boolean;
|
|
allowSetToDefault?: boolean;
|
|
disableToasts?: boolean;
|
|
isDryRun?: boolean;
|
|
noScheduleChildren?: ReactNode;
|
|
loadingStateChildren?: ReactNode;
|
|
};
|
|
|
|
export const AvailabilitySettingsPlatformWrapper = forwardRef<
|
|
AvailabilitySettingsFormRef,
|
|
AvailabilitySettingsPlatformWrapperProps
|
|
>(function AvailabilitySettingsPlatformWrapper(props, ref) {
|
|
const {
|
|
id,
|
|
customClassNames,
|
|
onDeleteError,
|
|
onDeleteSuccess,
|
|
onUpdateError,
|
|
onUpdateSuccess,
|
|
disableEditableHeading = false,
|
|
enableOverrides = false,
|
|
onBeforeUpdate,
|
|
onFormStateChange,
|
|
allowDelete,
|
|
allowSetToDefault,
|
|
disableToasts,
|
|
isDryRun = false,
|
|
noScheduleChildren,
|
|
loadingStateChildren,
|
|
} = props;
|
|
const { isLoading, data: atomSchedule } = useAtomSchedule(id);
|
|
const { data: me } = useMe();
|
|
const { timeFormat } = me?.data || { timeFormat: null };
|
|
const { toast } = useToast();
|
|
|
|
const { mutate: deleteSchedule, isPending: isDeletionInProgress } = useDeleteSchedule({
|
|
onSuccess: (res) => {
|
|
onDeleteSuccess?.(res);
|
|
if (!disableToasts) {
|
|
toast({
|
|
description: "Schedule deleted successfully",
|
|
});
|
|
}
|
|
},
|
|
onError: (err) => {
|
|
onDeleteError?.(err);
|
|
if (!disableToasts) {
|
|
toast({
|
|
description: "Could not delete schedule",
|
|
});
|
|
}
|
|
},
|
|
});
|
|
|
|
const callbacksRef = useRef<{ onSuccess?: () => void; onError?: (error: Error) => void }>({});
|
|
|
|
const { mutate: updateSchedule, isPending: isSavingInProgress } = useAtomUpdateSchedule({
|
|
onSuccess: (res) => {
|
|
onUpdateSuccess?.(res);
|
|
if (!disableToasts) {
|
|
toast({
|
|
description: "Schedule updated successfully",
|
|
});
|
|
}
|
|
callbacksRef.current?.onSuccess?.();
|
|
},
|
|
onError: (err) => {
|
|
onUpdateError?.(err);
|
|
if (!disableToasts) {
|
|
toast({
|
|
description: "Could not update schedule",
|
|
});
|
|
}
|
|
callbacksRef.current?.onError?.(err);
|
|
},
|
|
});
|
|
|
|
const handleDelete = async (id: number) => {
|
|
await deleteSchedule({ id });
|
|
};
|
|
|
|
const handleUpdate = async (id: number, body: AvailabilityFormValues) => {
|
|
let canUpdate = true;
|
|
|
|
if (onBeforeUpdate) {
|
|
canUpdate = await onBeforeUpdate(body);
|
|
}
|
|
|
|
if (canUpdate) {
|
|
updateSchedule({
|
|
scheduleId: id,
|
|
body: {
|
|
...body,
|
|
dateOverrides: body.dateOverrides.flatMap((override) => override.ranges),
|
|
},
|
|
});
|
|
}
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<>
|
|
{loadingStateChildren ? loadingStateChildren : <div className="px-10 py-4 text-xl">Loading...</div>}
|
|
</>
|
|
);
|
|
}
|
|
|
|
if (!atomSchedule) {
|
|
return noScheduleChildren ? (
|
|
<>{noScheduleChildren}</>
|
|
) : (
|
|
<div className="px-10 py-4 text-xl">No user schedule present</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<AtomsWrapper>
|
|
<AvailabilitySettings
|
|
ref={ref}
|
|
disableEditableHeading={disableEditableHeading}
|
|
handleDelete={() => {
|
|
if (isDryRun) {
|
|
toast({
|
|
description: "Schedule deleted successfully",
|
|
});
|
|
}
|
|
|
|
if (!isDryRun && atomSchedule.id) {
|
|
handleDelete(atomSchedule.id);
|
|
}
|
|
}}
|
|
handleSubmit={async (data) => {
|
|
if (isDryRun) {
|
|
toast({
|
|
description: "Schedule updated successfully",
|
|
});
|
|
}
|
|
|
|
if (!isDryRun && atomSchedule.id) {
|
|
handleUpdate(atomSchedule.id, data);
|
|
}
|
|
}}
|
|
weekStart={me?.data?.weekStart || "Sunday"}
|
|
timeFormat={timeFormat}
|
|
enableOverrides={enableOverrides}
|
|
isLoading={isLoading}
|
|
schedule={{
|
|
name: atomSchedule.name,
|
|
id: atomSchedule.id,
|
|
isLastSchedule: atomSchedule.isLastSchedule,
|
|
isDefault: atomSchedule.isDefault,
|
|
workingHours: atomSchedule.workingHours,
|
|
dateOverrides: atomSchedule.dateOverrides,
|
|
timeZone: atomSchedule.timeZone,
|
|
availability: atomSchedule.availability,
|
|
schedule:
|
|
atomSchedule.schedule.reduce(
|
|
(acc: Availability[], avail: Availability) => [
|
|
...acc,
|
|
{ days: avail.days, startTime: new Date(avail.startTime), endTime: new Date(avail.endTime) },
|
|
],
|
|
[]
|
|
) || [],
|
|
}}
|
|
isDeleting={isDeletionInProgress}
|
|
isSaving={isSavingInProgress}
|
|
backPath=""
|
|
isPlatform={true}
|
|
customClassNames={customClassNames}
|
|
allowDelete={allowDelete}
|
|
allowSetToDefault={allowSetToDefault}
|
|
onFormStateChange={onFormStateChange}
|
|
callbacksRef={callbacksRef}
|
|
isDryRun={isDryRun}
|
|
/>
|
|
</AtomsWrapper>
|
|
);
|
|
});
|