feat: update event types for default availability change (#13964)
* feat: update event types for default availability change * chore: add toast --------- Co-authored-by: sean-brydon <sean@cal.com> Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
This commit is contained in:
co-authored by
sean-brydon
sean-brydon
Udit Takkar
parent
1a645f3110
commit
9230b2d2ca
@@ -5,7 +5,7 @@ import { InstallAppButton } from "@calcom/app-store/components";
|
||||
import { getEventLocationTypeFromApp, type EventLocationType } from "@calcom/app-store/locations";
|
||||
import type { CredentialOwner } from "@calcom/app-store/types";
|
||||
import { AppSetDefaultLinkDialog } from "@calcom/features/apps/components/AppSetDefaultLinkDialog";
|
||||
import { BulkEditDefaultConferencingModal } from "@calcom/features/eventtypes/components/BulkEditDefaultConferencingModal";
|
||||
import { BulkEditDefaultForEventsModal } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { AppCategories } from "@calcom/prisma/enums";
|
||||
import { trpc, type RouterOutputs } from "@calcom/trpc";
|
||||
@@ -154,6 +154,12 @@ export const AppList = ({ data, handleDisconnect, variant, listClassName }: AppL
|
||||
});
|
||||
|
||||
const { t } = useLocale();
|
||||
const updateLocationsMutation = trpc.viewer.eventTypes.bulkUpdateToDefaultLocation.useMutation({
|
||||
onSuccess: () => {
|
||||
utils.viewer.getUsersDefaultConferencingApp.invalidate();
|
||||
setBulkUpdateModal(false);
|
||||
},
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<List className={listClassName}>
|
||||
@@ -173,7 +179,12 @@ export const AppList = ({ data, handleDisconnect, variant, listClassName }: AppL
|
||||
)}
|
||||
|
||||
{bulkUpdateModal && (
|
||||
<BulkEditDefaultConferencingModal open={bulkUpdateModal} setOpen={setBulkUpdateModal} />
|
||||
<BulkEditDefaultForEventsModal
|
||||
bulkUpdateFunction={updateLocationsMutation.mutate}
|
||||
open={bulkUpdateModal}
|
||||
setOpen={setBulkUpdateModal}
|
||||
isPending={updateLocationsMutation.isPending}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter, usePathname } from "next/navigation";
|
||||
import { useCallback } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import { BulkEditDefaultForEventsModal } 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";
|
||||
@@ -21,6 +22,7 @@ import SkeletonLoader from "@components/availability/SkeletonLoader";
|
||||
|
||||
export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availability"]["list"]) {
|
||||
const { t } = useLocale();
|
||||
const [bulkUpdateModal, setBulkUpdateModal] = useState(false);
|
||||
const utils = trpc.useContext();
|
||||
|
||||
const meQuery = trpc.viewer.me.useQuery();
|
||||
@@ -65,6 +67,7 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
|
||||
}),
|
||||
"success"
|
||||
);
|
||||
setBulkUpdateModal(true);
|
||||
},
|
||||
onError: (err) => {
|
||||
if (err instanceof HttpError) {
|
||||
@@ -74,6 +77,15 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
|
||||
},
|
||||
});
|
||||
|
||||
const bulkUpdateDefaultAvailabilityMutation =
|
||||
trpc.viewer.availability.schedule.bulkUpdateToDefaultAvailability.useMutation({
|
||||
onSuccess: () => {
|
||||
utils.viewer.availability.list.invalidate();
|
||||
setBulkUpdateModal(false);
|
||||
showToast(t("success"), "success");
|
||||
},
|
||||
});
|
||||
|
||||
const duplicateMutation = trpc.viewer.availability.schedule.duplicate.useMutation({
|
||||
onSuccess: async ({ schedule }) => {
|
||||
await router.push(`/availability/${schedule.id}`);
|
||||
@@ -129,6 +141,14 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
|
||||
{t("add_a_redirect")}
|
||||
</Link>
|
||||
</div>
|
||||
{bulkUpdateModal && (
|
||||
<BulkEditDefaultForEventsModal
|
||||
isPending={bulkUpdateDefaultAvailabilityMutation.isPending}
|
||||
open={bulkUpdateModal}
|
||||
setOpen={setBulkUpdateModal}
|
||||
bulkUpdateFunction={bulkUpdateDefaultAvailabilityMutation.mutate}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
+8
-10
@@ -10,7 +10,12 @@ export const BulkUpdateEventSchema = z.object({
|
||||
eventTypeIds: z.array(z.number()),
|
||||
});
|
||||
|
||||
export function BulkEditDefaultConferencingModal(props: { open: boolean; setOpen: (open: boolean) => void }) {
|
||||
export function BulkEditDefaultForEventsModal(props: {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
bulkUpdateFunction: ({ eventTypeIds }: { eventTypeIds: number[] }) => void;
|
||||
isPending: boolean;
|
||||
}) {
|
||||
const { t } = useLocale();
|
||||
const utils = trpc.useContext();
|
||||
const { data, isFetching } = trpc.viewer.eventTypes.bulkEventFetch.useQuery();
|
||||
@@ -21,13 +26,6 @@ export function BulkEditDefaultConferencingModal(props: { open: boolean; setOpen
|
||||
},
|
||||
});
|
||||
|
||||
const updateLocationsMutation = trpc.viewer.eventTypes.bulkUpdateToDefaultLocation.useMutation({
|
||||
onSuccess: () => {
|
||||
utils.viewer.getUsersDefaultConferencingApp.invalidate();
|
||||
props.setOpen(false);
|
||||
},
|
||||
});
|
||||
|
||||
const eventTypesSelected = form.watch("eventTypeIds");
|
||||
|
||||
if (isFetching || !open || !data?.eventTypes) return null;
|
||||
@@ -42,7 +40,7 @@ export function BulkEditDefaultConferencingModal(props: { open: boolean; setOpen
|
||||
<Form
|
||||
form={form}
|
||||
handleSubmit={(values) => {
|
||||
updateLocationsMutation.mutate(values);
|
||||
props.bulkUpdateFunction(values);
|
||||
}}>
|
||||
<div className="flex flex-col space-y-2">
|
||||
{data.eventTypes.length > 0 && (
|
||||
@@ -81,7 +79,7 @@ export function BulkEditDefaultConferencingModal(props: { open: boolean; setOpen
|
||||
utils.viewer.getUsersDefaultConferencingApp.invalidate();
|
||||
}}
|
||||
/>
|
||||
<Button type="submit" color="primary" loading={updateLocationsMutation.isPending}>
|
||||
<Button type="submit" color="primary" loading={props.isPending}>
|
||||
{t("update")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
@@ -1,5 +1,6 @@
|
||||
import authedProcedure from "../../../../procedures/authedProcedure";
|
||||
import { router } from "../../../../trpc";
|
||||
import { ZBulkUpdateToDefaultAvailabilityInputSchema } from "./bulkUpdateDefaultAvailability.schema";
|
||||
import { ZCreateInputSchema } from "./create.schema";
|
||||
import { ZDeleteInputSchema } from "./delete.schema";
|
||||
import { ZScheduleDuplicateSchema } from "./duplicate.schema";
|
||||
@@ -16,6 +17,7 @@ type ScheduleRouterHandlerCache = {
|
||||
duplicate?: typeof import("./duplicate.handler").duplicateHandler;
|
||||
getScheduleByUserId?: typeof import("./getScheduleByUserId.handler").getScheduleByUserIdHandler;
|
||||
getScheduleByEventSlug?: typeof import("./getScheduleByEventTypeSlug.handler").getScheduleByEventSlugHandler;
|
||||
bulkUpdateToDefaultAvailability?: typeof import("./bulkUpdateDefaultAvailability.handler").bulkUpdateToDefaultAvailabilityHandler;
|
||||
};
|
||||
|
||||
const UNSTABLE_HANDLER_CACHE: ScheduleRouterHandlerCache = {};
|
||||
@@ -137,4 +139,22 @@ export const scheduleRouter = router({
|
||||
input,
|
||||
});
|
||||
}),
|
||||
bulkUpdateToDefaultAvailability: authedProcedure
|
||||
.input(ZBulkUpdateToDefaultAvailabilityInputSchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
if (!UNSTABLE_HANDLER_CACHE.bulkUpdateToDefaultAvailability) {
|
||||
UNSTABLE_HANDLER_CACHE.bulkUpdateToDefaultAvailability = await import(
|
||||
"./bulkUpdateDefaultAvailability.handler"
|
||||
).then((mod) => mod.bulkUpdateToDefaultAvailabilityHandler);
|
||||
}
|
||||
|
||||
if (!UNSTABLE_HANDLER_CACHE.bulkUpdateToDefaultAvailability) {
|
||||
throw new Error("Failed to load handler");
|
||||
}
|
||||
|
||||
return UNSTABLE_HANDLER_CACHE.bulkUpdateToDefaultAvailability({
|
||||
ctx,
|
||||
input,
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
import { prisma } from "@calcom/prisma";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
import type { TrpcSessionUser } from "../../../../trpc";
|
||||
import type { TBulkUpdateToDefaultAvailabilityInputSchema } from "./bulkUpdateDefaultAvailability.schema";
|
||||
|
||||
type BulkUpdateToDefaultAvailabilityOptions = {
|
||||
ctx: {
|
||||
user: NonNullable<TrpcSessionUser>;
|
||||
};
|
||||
input: TBulkUpdateToDefaultAvailabilityInputSchema;
|
||||
};
|
||||
|
||||
export const bulkUpdateToDefaultAvailabilityHandler = async ({
|
||||
ctx,
|
||||
input,
|
||||
}: BulkUpdateToDefaultAvailabilityOptions) => {
|
||||
const { eventTypeIds } = input;
|
||||
const defaultScheduleId = ctx.user.defaultScheduleId;
|
||||
|
||||
if (!defaultScheduleId) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Default schedule not set",
|
||||
});
|
||||
}
|
||||
|
||||
return await prisma.eventType.updateMany({
|
||||
where: {
|
||||
id: {
|
||||
in: eventTypeIds,
|
||||
},
|
||||
userId: ctx.user.id,
|
||||
},
|
||||
data: {
|
||||
scheduleId: defaultScheduleId,
|
||||
},
|
||||
});
|
||||
};
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const ZBulkUpdateToDefaultAvailabilityInputSchema = z.object({
|
||||
eventTypeIds: z.array(z.number()),
|
||||
});
|
||||
|
||||
export type TBulkUpdateToDefaultAvailabilityInputSchema = z.infer<
|
||||
typeof ZBulkUpdateToDefaultAvailabilityInputSchema
|
||||
>;
|
||||
Reference in New Issue
Block a user