From 6adc29c9cc8a6d4cbd3fb549b7ec3b010f139a06 Mon Sep 17 00:00:00 2001 From: MehulZR Date: Fri, 24 Jan 2025 05:09:59 +0530 Subject: [PATCH 1/2] fix: bulk update event type availability --- .../[category]/installed-category-view.tsx | 4 +- .../availability/[schedule]/schedule-view.tsx | 39 +++++++++++-------- .../availability/availability-view.tsx | 4 +- packages/features/apps/components/AppList.tsx | 4 +- .../BulkEditDefaultForEventsModal.tsx | 4 +- .../availability/AvailabilitySettings.tsx | 4 +- .../ConferencingAppsViewPlatformWrapper.tsx | 4 +- .../ConferencingAppsViewWebWrapper.tsx | 4 +- 8 files changed, 36 insertions(+), 31 deletions(-) diff --git a/apps/web/modules/apps/installed/[category]/installed-category-view.tsx b/apps/web/modules/apps/installed/[category]/installed-category-view.tsx index ba392420aa8628..f3644af24c8e7e 100644 --- a/apps/web/modules/apps/installed/[category]/installed-category-view.tsx +++ b/apps/web/modules/apps/installed/[category]/installed-category-view.tsx @@ -7,7 +7,7 @@ import { AppList, type HandleDisconnect } from "@calcom/features/apps/components import type { UpdateUsersDefaultConferencingAppParams } from "@calcom/features/apps/components/AppSetDefaultLinkDialog"; import DisconnectIntegrationModal from "@calcom/features/apps/components/DisconnectIntegrationModal"; import type { RemoveAppParams } from "@calcom/features/apps/components/DisconnectIntegrationModal"; -import type { BulkUpdatParams } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; +import type { BulkUpdateParams } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { AppCategories } from "@calcom/prisma/enums"; @@ -78,7 +78,7 @@ const IntegrationsContainer = ({ ); }; - const handleBulkUpdateDefaultLocation = ({ eventTypeIds, callback }: BulkUpdatParams) => { + const handleBulkUpdateDefaultLocation = ({ eventTypeIds, callback }: BulkUpdateParams) => { updateLocationsMutation.mutate( { eventTypeIds, diff --git a/apps/web/modules/availability/[schedule]/schedule-view.tsx b/apps/web/modules/availability/[schedule]/schedule-view.tsx index fc5a8abad00cb2..d176e55a9343e1 100644 --- a/apps/web/modules/availability/[schedule]/schedule-view.tsx +++ b/apps/web/modules/availability/[schedule]/schedule-view.tsx @@ -4,7 +4,7 @@ import { useRouter } from "next/navigation"; import { useState } from "react"; import { AvailabilitySettings } from "@calcom/atoms/monorepo"; -import type { BulkUpdatParams } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; +import type { BulkUpdateParams } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; import { withErrorFromUnknown } from "@calcom/lib/getClientErrorFromUnknown"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLocale } from "@calcom/lib/hooks/useLocale"; @@ -53,19 +53,9 @@ export const AvailabilitySettingsWebWrapper = ({ const { data: eventTypesQueryData, isFetching: isEventTypesFetching } = trpc.viewer.eventTypes.bulkEventFetch.useQuery(); - const bulkUpdateFunction = ({ eventTypeIds, callback }: BulkUpdatParams) => { - bulkUpdateDefaultAvailabilityMutation.mutate( - { - eventTypeIds, - }, - { - onSuccess: () => { - utils.viewer.availability.list.invalidate(); - callback(); - showToast(t("success"), "success"); - }, - } - ); + const bulkUpdateFunction = ({ eventTypeIds, callback }: BulkUpdateParams) => { + setBulkUpdateEventTypeIds(eventTypeIds); + callback(); }; const handleBulkEditDialogToggle = () => { @@ -114,6 +104,8 @@ export const AvailabilitySettingsWebWrapper = ({ }, }); + const [bulkUpdateEventTypeIds, setBulkUpdateEventTypeIds] = useState([]); + // TODO: reimplement Skeletons for this page in here if (isPending) return null; @@ -137,18 +129,31 @@ export const AvailabilitySettingsWebWrapper = ({ scheduleId && deleteMutation.mutate({ scheduleId }); }} handleSubmit={async ({ dateOverrides, ...values }) => { - scheduleId && - updateMutation.mutate({ + if (scheduleId) { + await updateMutation.mutateAsync({ scheduleId, dateOverrides: dateOverrides.flatMap((override) => override.ranges), ...values, }); + + if (!values.isDefault || !bulkUpdateEventTypeIds.length) return; + + bulkUpdateDefaultAvailabilityMutation.mutate( + { eventTypeIds: bulkUpdateEventTypeIds }, + { + onSuccess: () => { + utils.viewer.availability.list.invalidate(); + showToast(t("success"), "success"); + }, + } + ); + } }} bulkUpdateModalProps={{ isOpen: isBulkUpdateModalOpen, setIsOpen: setIsBulkUpdateModalOpen, save: bulkUpdateFunction, - isSaving: bulkUpdateDefaultAvailabilityMutation.isPending, + isSaving: false, eventTypes: eventTypesQueryData?.eventTypes, isEventTypesFetching, handleBulkEditDialogToggle: handleBulkEditDialogToggle, diff --git a/apps/web/modules/availability/availability-view.tsx b/apps/web/modules/availability/availability-view.tsx index 0f79c2d68f9460..7ea2eb2441ac3d 100644 --- a/apps/web/modules/availability/availability-view.tsx +++ b/apps/web/modules/availability/availability-view.tsx @@ -7,7 +7,7 @@ import { useCallback, useState } from "react"; import SkeletonLoader from "@calcom/features/availability/components/SkeletonLoader"; import { BulkEditDefaultForEventsModal } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; -import type { BulkUpdatParams } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; +import type { BulkUpdateParams } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; import { NewScheduleButton, ScheduleListItem } from "@calcom/features/schedules"; import Shell from "@calcom/features/shell/Shell"; import { AvailabilitySliderTable } from "@calcom/features/timezone-buddy/components/AvailabilitySliderTable"; @@ -86,7 +86,7 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab const { data: eventTypesQueryData, isFetching: isEventTypesFetching } = trpc.viewer.eventTypes.bulkEventFetch.useQuery(); - const bulkUpdateFunction = ({ eventTypeIds, callback }: BulkUpdatParams) => { + const bulkUpdateFunction = ({ eventTypeIds, callback }: BulkUpdateParams) => { bulkUpdateDefaultAvailabilityMutation.mutate( { eventTypeIds, diff --git a/packages/features/apps/components/AppList.tsx b/packages/features/apps/components/AppList.tsx index e29c9e3e60cedd..70d005043f14cc 100644 --- a/packages/features/apps/components/AppList.tsx +++ b/packages/features/apps/components/AppList.tsx @@ -8,7 +8,7 @@ import AppListCard from "@calcom/features/apps/components/AppListCard"; import type { UpdateUsersDefaultConferencingAppParams } from "@calcom/features/apps/components/AppSetDefaultLinkDialog"; import { AppSetDefaultLinkDialog } from "@calcom/features/apps/components/AppSetDefaultLinkDialog"; import type { - BulkUpdatParams, + BulkUpdateParams, EventTypes, } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; import { BulkEditDefaultForEventsModal } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; @@ -37,7 +37,7 @@ interface AppListProps { listClassName?: string; defaultConferencingApp: RouterOutputs["viewer"]["getUsersDefaultConferencingApp"]; handleUpdateUserDefaultConferencingApp: (params: UpdateUsersDefaultConferencingAppParams) => void; - handleBulkUpdateDefaultLocation: (params: BulkUpdatParams) => void; + handleBulkUpdateDefaultLocation: (params: BulkUpdateParams) => void; isBulkUpdateDefaultLocationPending: boolean; eventTypes?: EventTypes; isEventTypesFetching?: boolean; diff --git a/packages/features/eventtypes/components/BulkEditDefaultForEventsModal.tsx b/packages/features/eventtypes/components/BulkEditDefaultForEventsModal.tsx index 39222328a7d133..39fdd88f25d318 100644 --- a/packages/features/eventtypes/components/BulkEditDefaultForEventsModal.tsx +++ b/packages/features/eventtypes/components/BulkEditDefaultForEventsModal.tsx @@ -9,7 +9,7 @@ export const BulkUpdateEventSchema = z.object({ eventTypeIds: z.array(z.number()), }); -export type BulkUpdatParams = { eventTypeIds: number[]; callback: () => void }; +export type BulkUpdateParams = { eventTypeIds: number[]; callback: () => void }; export type EventTypes = Array<{ id: number; title: string }>; export function BulkEditDefaultForEventsModal({ @@ -19,7 +19,7 @@ export function BulkEditDefaultForEventsModal({ }: { open: boolean; setOpen: (open: boolean) => void; - bulkUpdateFunction: (params: BulkUpdatParams) => void; + bulkUpdateFunction: (params: BulkUpdateParams) => void; isPending: boolean; description: string; isEventTypesFetching?: boolean; diff --git a/packages/platform/atoms/availability/AvailabilitySettings.tsx b/packages/platform/atoms/availability/AvailabilitySettings.tsx index dc9b3c95dc39cc..2627fa8f3b780c 100644 --- a/packages/platform/atoms/availability/AvailabilitySettings.tsx +++ b/packages/platform/atoms/availability/AvailabilitySettings.tsx @@ -6,7 +6,7 @@ import { Controller, useFieldArray, useForm, useFormContext, useWatch } from "re import dayjs from "@calcom/dayjs"; import type { - BulkUpdatParams, + BulkUpdateParams, EventTypes, } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; import { BulkEditDefaultForEventsModal } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal"; @@ -110,7 +110,7 @@ type AvailabilitySettingsProps = { bulkUpdateModalProps?: { isOpen: boolean; setIsOpen: Dispatch>; - save: (params: BulkUpdatParams) => void; + save: (params: BulkUpdateParams) => void; isSaving: boolean; eventTypes?: EventTypes; isEventTypesFetching?: boolean; diff --git a/packages/platform/atoms/connect/conferencing-apps/ConferencingAppsViewPlatformWrapper.tsx b/packages/platform/atoms/connect/conferencing-apps/ConferencingAppsViewPlatformWrapper.tsx index 22b9dac7444e4c..8e38b40f76fcd3 100644 --- a/packages/platform/atoms/connect/conferencing-apps/ConferencingAppsViewPlatformWrapper.tsx +++ b/packages/platform/atoms/connect/conferencing-apps/ConferencingAppsViewPlatformWrapper.tsx @@ -26,7 +26,7 @@ import { import { AtomsWrapper } from "../../src/components/atoms-wrapper"; import { useToast } from "../../src/components/ui/use-toast"; import type { - BulkUpdatParams, + BulkUpdateParams, UpdateUsersDefaultConferencingAppParams, } from "./ConferencingAppsViewWebWrapper"; import { useAtomBulkUpdateEventTypesToDefaultLocation } from "./hooks/useAtomBulkUpdateEventTypesToDefaultLocation"; @@ -149,7 +149,7 @@ export const ConferencingAppsViewPlatformWrapper = ({ }); }; - const handleBulkUpdateDefaultLocation = ({ eventTypeIds, callback }: BulkUpdatParams) => { + const handleBulkUpdateDefaultLocation = ({ eventTypeIds, callback }: BulkUpdateParams) => { bulkUpdateEventTypesToDefaultLocation.mutate(eventTypeIds, { onSuccess: () => { queryClient.invalidateQueries({ queryKey: [defaultConferencingAppQueryKey] }); diff --git a/packages/platform/atoms/connect/conferencing-apps/ConferencingAppsViewWebWrapper.tsx b/packages/platform/atoms/connect/conferencing-apps/ConferencingAppsViewWebWrapper.tsx index 5fd3e4b063dd1f..5335b3ec8a71eb 100644 --- a/packages/platform/atoms/connect/conferencing-apps/ConferencingAppsViewWebWrapper.tsx +++ b/packages/platform/atoms/connect/conferencing-apps/ConferencingAppsViewWebWrapper.tsx @@ -23,7 +23,7 @@ export type UpdateUsersDefaultConferencingAppParams = { onErrorCallback: () => void; }; -export type BulkUpdatParams = { eventTypeIds: number[]; callback: () => void }; +export type BulkUpdateParams = { eventTypeIds: number[]; callback: () => void }; type RemoveAppParams = { credentialId: number; teamId?: number; callback: () => void }; const SkeletonLoader = () => { @@ -130,7 +130,7 @@ export const ConferencingAppsViewWebWrapper = ({ ); }; - const handleBulkUpdateDefaultLocation = ({ eventTypeIds, callback }: BulkUpdatParams) => { + const handleBulkUpdateDefaultLocation = ({ eventTypeIds, callback }: BulkUpdateParams) => { updateLocationsMutation.mutate( { eventTypeIds, From 870c85555f55a4174a3ad4580bb665efcf02551f Mon Sep 17 00:00:00 2001 From: MehulZR Date: Fri, 24 Jan 2025 19:51:03 +0530 Subject: [PATCH 2/2] error handling & preventing bulk update mutation if schedule update fails --- .../web/modules/availability/[schedule]/schedule-view.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/web/modules/availability/[schedule]/schedule-view.tsx b/apps/web/modules/availability/[schedule]/schedule-view.tsx index d176e55a9343e1..184612ff25d5cc 100644 --- a/apps/web/modules/availability/[schedule]/schedule-view.tsx +++ b/apps/web/modules/availability/[schedule]/schedule-view.tsx @@ -136,7 +136,7 @@ export const AvailabilitySettingsWebWrapper = ({ ...values, }); - if (!values.isDefault || !bulkUpdateEventTypeIds.length) return; + if (!values.isDefault || !bulkUpdateEventTypeIds.length || updateMutation.isError) return; bulkUpdateDefaultAvailabilityMutation.mutate( { eventTypeIds: bulkUpdateEventTypeIds }, @@ -145,6 +145,12 @@ export const AvailabilitySettingsWebWrapper = ({ utils.viewer.availability.list.invalidate(); showToast(t("success"), "success"); }, + onError: (err) => { + if (err instanceof HttpError) { + const message = `${err.statusCode}: ${err.message}`; + showToast(message, "error"); + } + }, } ); }