Files
calendar/apps/web/modules/availability/[schedule]/schedule-view.tsx
T
Benny JooandGitHub 6815f2f9c7 perf: server-side fetching for /availability (#20804)
* availability

* refactor

* add loader

* improve

* update

* fix loader

* rename

* satisfying types

* refactor

* remove log

* add CTA to skeleton

* refactor

* fix revalidations

* refactor

* update

* finish
2025-04-24 11:10:54 +02:00

142 lines
5.2 KiB
TypeScript

"use client";
import { revalidateAvailabilityList } from "app/(use-page-wrapper)/(main-nav)/availability/actions";
import { revalidateSchedulePage } from "app/(use-page-wrapper)/availability/[schedule]/actions";
import { useRouter, useSearchParams } from "next/navigation";
import { useState } from "react";
import { AvailabilitySettings } from "@calcom/atoms/availability/AvailabilitySettings";
import type { BulkUpdatParams } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal";
import { withErrorFromUnknown } from "@calcom/lib/getClientErrorFromUnknown";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { HttpError } from "@calcom/lib/http-error";
import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
import { showToast } from "@calcom/ui/components/toast";
type PageProps = {
scheduleData: RouterOutputs["viewer"]["availability"]["schedule"]["get"];
travelSchedulesData: RouterOutputs["viewer"]["travelSchedules"]["get"];
};
export const AvailabilitySettingsWebWrapper = ({
scheduleData: schedule,
travelSchedulesData: travelSchedules,
}: PageProps) => {
const searchParams = useSearchParams();
const { t } = useLocale();
const router = useRouter();
const utils = trpc.useUtils();
const me = useMeQuery();
const fromEventType = searchParams?.get("fromEventType");
const scheduleId = schedule.id;
const { timeFormat } = me.data || { timeFormat: null };
const [isBulkUpdateModalOpen, setIsBulkUpdateModalOpen] = useState(false);
const bulkUpdateDefaultAvailabilityMutation =
trpc.viewer.availability.schedule.bulkUpdateToDefaultAvailability.useMutation();
const { data: eventTypesQueryData, isFetching: isEventTypesFetching } =
trpc.viewer.eventTypes.bulkEventFetch.useQuery();
const bulkUpdateFunction = ({ eventTypeIds, callback }: BulkUpdatParams) => {
bulkUpdateDefaultAvailabilityMutation.mutate(
{
eventTypeIds,
selectedDefaultScheduleId: scheduleId,
},
{
onSuccess: () => {
utils.viewer.availability.list.invalidate();
revalidateAvailabilityList();
callback();
showToast(t("success"), "success");
},
}
);
};
const handleBulkEditDialogToggle = () => {
utils.viewer.apps.getUsersDefaultConferencingApp.invalidate();
};
const isDefaultSchedule = me.data?.defaultScheduleId === scheduleId;
const updateMutation = trpc.viewer.availability.schedule.update.useMutation({
onSuccess: async ({ prevDefaultId, currentDefaultId, ...data }) => {
if (prevDefaultId && currentDefaultId) {
// check weather the default schedule has been changed by comparing previous default schedule id and current default schedule id.
if (prevDefaultId !== currentDefaultId) {
// if not equal, invalidate previous default schedule id and refetch previous default schedule id.
utils.viewer.availability.schedule.get.invalidate({ scheduleId: prevDefaultId });
utils.viewer.availability.schedule.get.refetch({ scheduleId: prevDefaultId });
}
}
utils.viewer.availability.schedule.get.invalidate({ scheduleId: data.schedule.id });
revalidateSchedulePage(scheduleId);
utils.viewer.availability.list.invalidate();
revalidateAvailabilityList();
showToast(
t("availability_updated_successfully", {
scheduleName: data.schedule.name,
}),
"success"
);
},
onError: (err) => {
if (err instanceof HttpError) {
const message = `${err.statusCode}: ${err.message}`;
showToast(message, "error");
}
},
});
const deleteMutation = trpc.viewer.availability.schedule.delete.useMutation({
onError: withErrorFromUnknown((err) => {
showToast(err.message, "error");
}),
onSettled: () => {
utils.viewer.availability.list.invalidate();
},
onSuccess: () => {
showToast(t("schedule_deleted_successfully"), "success");
revalidateAvailabilityList();
router.push("/availability");
},
});
return (
<AvailabilitySettings
schedule={schedule}
travelSchedules={isDefaultSchedule ? travelSchedules || [] : []}
isDeleting={deleteMutation.isPending}
isLoading={false}
isSaving={updateMutation.isPending}
enableOverrides={true}
timeFormat={timeFormat}
weekStart={me.data?.weekStart || "Sunday"}
backPath={fromEventType ? true : "/availability"}
handleDelete={() => {
scheduleId && deleteMutation.mutate({ scheduleId });
}}
handleSubmit={async ({ dateOverrides, ...values }) => {
scheduleId &&
updateMutation.mutate({
scheduleId,
dateOverrides: dateOverrides.flatMap((override) => override.ranges),
...values,
});
}}
bulkUpdateModalProps={{
isOpen: isBulkUpdateModalOpen,
setIsOpen: setIsBulkUpdateModalOpen,
save: bulkUpdateFunction,
isSaving: bulkUpdateDefaultAvailabilityMutation.isPending,
eventTypes: eventTypesQueryData?.eventTypes,
isEventTypesFetching,
handleBulkEditDialogToggle: handleBulkEditDialogToggle,
}}
/>
);
};