Skip to content

Commit

Permalink
Merge branch 'main' into workflow_link_issue
Browse files Browse the repository at this point in the history
  • Loading branch information
zomars authored Oct 15, 2024
2 parents 6538956 + 9c3f4ec commit cfedb99
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 43 deletions.
65 changes: 40 additions & 25 deletions packages/features/eventtypes/components/EventType.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,40 @@ export type EventTypeSetup = RouterOutputs["viewer"]["eventTypes"]["get"]["event
export type EventTypeAssignedUsers = RouterOutputs["viewer"]["eventTypes"]["get"]["eventType"]["children"];
export type EventTypeHosts = RouterOutputs["viewer"]["eventTypes"]["get"]["eventType"]["hosts"];

export const EventType = (
props: EventTypeSetupProps & {
allActiveWorkflows?: Workflow[];
tabMap: TabMap;
onDelete: (id: number) => void;
isDeleting?: boolean;
onConflict: (eventTypes: ChildrenEventType[]) => void;
children?: React.ReactNode;
handleSubmit: (values: FormValues) => void;
formMethods: UseFormReturn<FormValues>;
eventTypeApps?: EventTypeApps;
isUpdating: boolean;
isPlatform?: boolean;
tabName: (typeof tabs)[number];
tabsNavigation: VerticalTabItemProps[];
}
) => {
const { formMethods, isPlatform, tabName } = props;
const { eventType, team, currentUserMembership, tabMap, isUpdating } = props;
export type EventTypeComponentProps = EventTypeSetupProps & {
allActiveWorkflows?: Workflow[];
tabMap: TabMap;
onDelete: (id: number) => void;
isDeleting?: boolean;
onConflict: (eventTypes: ChildrenEventType[]) => void;
children?: React.ReactNode;
handleSubmit: (values: FormValues) => void;
formMethods: UseFormReturn<FormValues>;
eventTypeApps?: EventTypeApps;
isUpdating: boolean;
isPlatform?: boolean;
tabName: (typeof tabs)[number];
tabsNavigation: VerticalTabItemProps[];
allowDelete?: boolean;
};

export const EventType = ({
formMethods,
isPlatform,
tabName,
eventType,
team,
currentUserMembership,
tabMap,
isUpdating,
isUserOrganizationAdmin,
onDelete,
isDeleting,
tabsNavigation,
handleSubmit,
children,
allowDelete = true,
}: EventTypeComponentProps) => {
const [animationParentRef] = useAutoAnimate<HTMLDivElement>();

return (
Expand All @@ -80,16 +94,17 @@ export const EventType = (
disableBorder={true}
currentUserMembership={currentUserMembership}
bookerUrl={eventType.bookerUrl}
isUserOrganizationAdmin={props.isUserOrganizationAdmin}
onDelete={props.onDelete}
isDeleting={props.isDeleting}
isUserOrganizationAdmin={isUserOrganizationAdmin}
onDelete={onDelete}
isDeleting={isDeleting}
isPlatform={isPlatform}
tabsNavigation={props.tabsNavigation}>
<Form form={formMethods} id="event-type-form" handleSubmit={props.handleSubmit}>
allowDelete={allowDelete}
tabsNavigation={tabsNavigation}>
<Form form={formMethods} id="event-type-form" handleSubmit={handleSubmit}>
<div ref={animationParentRef}>{tabMap[tabName]}</div>
</Form>
</EventTypeSingleLayout>
{props.children}
{children}
</>
);
};
28 changes: 16 additions & 12 deletions packages/features/eventtypes/components/EventTypeLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type Props = {
isDeleting?: boolean;
isPlatform?: boolean;
tabsNavigation: VerticalTabItemProps[];
allowDelete?: boolean;
};

function EventTypeSingleLayout({
Expand All @@ -63,6 +64,7 @@ function EventTypeSingleLayout({
isDeleting,
isPlatform,
tabsNavigation,
allowDelete = true,
}: Props) {
const { t } = useLocale();
const eventTypesLockedByOrg = eventType.team?.parent?.organizationSettings?.lockEventTypeCreationForUsers;
Expand Down Expand Up @@ -187,7 +189,7 @@ function EventTypeSingleLayout({
)}
</>
)}
{!isChildrenManagedEventType && (
{!isChildrenManagedEventType && allowDelete && (
<Button
color="destructive"
variant="icon"
Expand All @@ -201,7 +203,7 @@ function EventTypeSingleLayout({
)}
</ButtonGroup>

<VerticalDivider className="hidden lg:block" />
{(!isPlatform || (isPlatform && allowDelete)) && <VerticalDivider className="hidden lg:block" />}

<Dropdown>
<DropdownMenuTrigger asChild>
Expand Down Expand Up @@ -229,16 +231,18 @@ function EventTypeSingleLayout({
{t("copy_link")}
</DropdownItem>
</DropdownMenuItem>
<DropdownMenuItem className="focus:ring-muted">
<DropdownItem
type="button"
color="destructive"
StartIcon="trash"
disabled={!hasPermsToDelete}
onClick={() => setDeleteDialogOpen(true)}>
{t("delete")}
</DropdownItem>
</DropdownMenuItem>
{allowDelete && (
<DropdownMenuItem className="focus:ring-muted">
<DropdownItem
type="button"
color="destructive"
StartIcon="trash"
disabled={!hasPermsToDelete}
onClick={() => setDeleteDialogOpen(true)}>
{t("delete")}
</DropdownItem>
</DropdownMenuItem>
)}
<DropdownMenuSeparator />
<div className="hover:bg-subtle flex h-9 cursor-pointer flex-row items-center justify-between px-4 py-2 transition">
<Skeleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { EventTypeSetupProps, FormValues, TabMap } from "@calcom/features/e
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { SchedulingType } from "@calcom/prisma/enums";

import { useDeleteEventTypeById } from "../../hooks/event-types/private/useDeleteEventTypeById";
import { useMe } from "../../hooks/useMe";
import { AtomsWrapper } from "../../src/components/atoms-wrapper";
import { useToast } from "../../src/components/ui/use-toast";
Expand All @@ -30,10 +31,19 @@ export type EventTypePlatformWrapperProps = {
tabs?: PlatformTabs[];
onSuccess?: (eventType: FormValues) => void;
onError?: (eventType: FormValues, error: Error) => void;
onDeleteSuccess?: () => void;
onDeleteError?: (msg: string) => void;
allowDelete: boolean;
};

const EventType = ({
tabs = ["setup", "availability", "team", "limits", "advanced", "recurring"],
onSuccess,
onError,
onDeleteSuccess,
onDeleteError,
id,
allowDelete = true,
...props
}: EventTypeSetupProps & EventTypePlatformWrapperProps) => {
const { t } = useLocale();
Expand All @@ -46,6 +56,20 @@ const EventType = ({
const [slugExistsChildrenDialogOpen, setSlugExistsChildrenDialogOpen] = useState<ChildrenEventType[]>([]);
const { data: user, isLoading: isUserLoading } = useMe();

const deleteMutation = useDeleteEventTypeById({
onSuccess: async () => {
showToast(t("event_type_deleted_successfully"), "success");
isTeamEventTypeDeleted.current = true;
setSlugExistsChildrenDialogOpen([]);
setIsOpenAssignmentWarnDialog(false);
onDeleteSuccess?.();
},
onError: (err) => {
showToast(err.message, "error");
onDeleteError?.(err.message);
},
});

const updateMutation = useAtomUpdateEventType({
onSuccess: async () => {
const currentValues = form.getValues();
Expand All @@ -58,7 +82,6 @@ const EventType = ({

// Reset the form with these values as new default values to ensure the correct comparison for dirtyFields eval
form.reset(currentValues);

toast({ description: t("event_type_updated_successfully", { eventTypeTitle: eventType.title }) });
onSuccess?.(currentValues);
},
Expand Down Expand Up @@ -141,7 +164,10 @@ const EventType = ({
});

const onDelete = () => {
isTeamEventTypeDeleted.current = true;
if (allowDelete) {
isTeamEventTypeDeleted.current = true;
deleteMutation.mutate(id);
}
};
const onConflict = (conflicts: ChildrenEventType[]) => {
setSlugExistsChildrenDialogOpen(conflicts);
Expand All @@ -165,7 +191,8 @@ const EventType = ({
isUpdating={updateMutation.isPending}
isPlatform
tabName={currentTab}
tabsNavigation={tabsNavigation}>
tabsNavigation={tabsNavigation}
allowDelete={allowDelete}>
<>
{slugExistsChildrenDialogOpen.length ? (
<ManagedEventTypeDialog
Expand All @@ -188,7 +215,15 @@ const EventType = ({
);
};

export const EventTypePlatformWrapper = ({ id, tabs, onSuccess, onError }: EventTypePlatformWrapperProps) => {
export const EventTypePlatformWrapper = ({
id,
tabs,
onSuccess,
onError,
onDeleteSuccess,
onDeleteError,
allowDelete = true,
}: EventTypePlatformWrapperProps) => {
const { data: eventTypeQueryData } = useAtomsEventTypeById(id);
const queryClient = useQueryClient();

Expand All @@ -208,5 +243,16 @@ export const EventTypePlatformWrapper = ({ id, tabs, onSuccess, onError }: Event

if (!eventTypeQueryData) return null;

return <EventType {...eventTypeQueryData} id={id} tabs={tabs} onSuccess={onSuccess} onError={onError} />;
return (
<EventType
{...eventTypeQueryData}
id={id}
tabs={tabs}
onSuccess={onSuccess}
onError={onError}
onDeleteSuccess={onDeleteSuccess}
onDeleteError={onDeleteError}
allowDelete={allowDelete}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useMutation } from "@tanstack/react-query";

import { V2_ENDPOINTS, SUCCESS_STATUS } from "@calcom/platform-constants";
import type { ApiResponse, ApiSuccessResponse } from "@calcom/platform-types";
import type { EventType } from "@calcom/prisma/client";

import http from "../../../lib/http";

export const QUERY_KEY = "use-delete-event-by-id";
export type UseDeleteEventTypeProps = {
onSuccess?: () => void;
onError?: (err: Error) => void;
onSettled?: () => void;
};
export const useDeleteEventTypeById = ({ onSuccess, onError, onSettled }: UseDeleteEventTypeProps) => {
return useMutation({
onSuccess,
onError,
onSettled,
mutationFn: (id: number) => {
if (!id) throw new Error("Event type id is required");
const pathname = `/${V2_ENDPOINTS.eventTypes}/${id}`;
return http?.delete<ApiResponse<EventType>>(pathname).then((res) => {
if (res.data.status === SUCCESS_STATUS) {
return (res.data as ApiSuccessResponse<EventType>).data;
}
throw new Error(res.data.error.message);
});
},
});
};
13 changes: 12 additions & 1 deletion packages/platform/examples/base/src/pages/event-types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ export default function Bookings(props: { calUsername: string; calEmail: string
const router = useRouter();
const { isLoading: isLoadingEvents, data: eventTypes, refetch } = useEventTypes(props.calUsername);
const { data: teams } = useTeams();
const { isLoading: isLoadingTeamEvents, data: teamEventTypes } = useTeamEventTypes(teams?.[0]?.id || 0);
const {
isLoading: isLoadingTeamEvents,
data: teamEventTypes,
refetch: refetchTeamEvents,
} = useTeamEventTypes(teams?.[0]?.id || 0);
const rescheduleUid = (router.query.rescheduleUid as string) ?? "";

return (
Expand Down Expand Up @@ -85,6 +89,7 @@ export default function Bookings(props: { calUsername: string; calEmail: string
{eventTypeId && (
<div>
<EventTypeSettings
allowDelete={true}
id={eventTypeId}
tabs={["setup", "limits", "recurring", "advanced"]}
onSuccess={(eventType) => {
Expand All @@ -96,6 +101,12 @@ export default function Bookings(props: { calUsername: string; calEmail: string
console.log(eventType);
console.error(error);
}}
onDeleteSuccess={() => {
refetch();
refetchTeamEvents();
setEventTypeId(null);
}}
onDeleteError={console.error}
/>
</div>
)}
Expand Down

0 comments on commit cfedb99

Please sign in to comment.