Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Delete the booking history of past meetings #18787 #19118

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ab424a7
Add delete button functionality to past bookings
Feb 5, 2025
65497f9
Merge branch 'main' of https://github.com/PAVANNAIK25/cal.com into fe…
Feb 5, 2025
559639f
Remove text variables from other languages
PAVANNAIK25 Feb 16, 2025
ad18631
add handler whwere offer seats case is handled
PAVANNAIK25 Feb 16, 2025
9c7906c
Merge branch 'main' into feat/delete-booking-history-past
TusharBhatt1 Feb 17, 2025
d49bf0d
update changes according to PR feedback
PAVANNAIK25 Feb 17, 2025
a39ac0a
Remove logs
PAVANNAIK25 Feb 17, 2025
bf28c12
Add tests to check the delete operation
PAVANNAIK25 Feb 17, 2025
0de08b8
Add test for past booking delete functionality
PAVANNAIK25 Feb 19, 2025
0d30ea4
Add dynamic import
PAVANNAIK25 Feb 19, 2025
351d8cc
Merge branch 'main' into feat/delete-booking-history-past
TusharBhatt1 Feb 19, 2025
485ce0e
Correct title for test
PAVANNAIK25 Feb 19, 2025
342b264
Merge branch 'feat/delete-booking-history-past' of https://github.com…
PAVANNAIK25 Feb 19, 2025
b1e4737
fix title and description
PAVANNAIK25 Feb 19, 2025
cc2787a
Merge branch 'main' into feat/delete-booking-history-past
TusharBhatt1 Feb 19, 2025
4e1a396
Remove unnecessary changes in locales
PAVANNAIK25 Feb 19, 2025
013eef1
Merge branch 'feat/delete-booking-history-past' of https://github.com…
PAVANNAIK25 Feb 19, 2025
3200003
Merge branch 'main' into feat/delete-booking-history-past
TusharBhatt1 Feb 21, 2025
d74432c
Merge branch 'main' into feat/delete-booking-history-past
TusharBhatt1 Feb 21, 2025
ac4c6ec
Merge branch 'main' into feat/delete-booking-history-past
anikdhabal Mar 3, 2025
19a45f9
Update common.json
anikdhabal Mar 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions apps/web/components/booking/BookingListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import assignmentReasonBadgeTitleMap from "@lib/booking/assignmentReasonBadgeTit

import { AddGuestsDialog } from "@components/dialog/AddGuestsDialog";
import { ChargeCardDialog } from "@components/dialog/ChargeCardDialog";
import DeleteHistoryDialog from "@components/dialog/DeleteHistoryDialog";
import { EditLocationDialog } from "@components/dialog/EditLocationDialog";
import { ReassignDialog } from "@components/dialog/ReassignDialog";
import { RerouteDialog } from "@components/dialog/RerouteDialog";
Expand Down Expand Up @@ -291,6 +292,18 @@ function BookingListItem(booking: BookingItemProps) {
});
}

if (isBookingInPast) {
editBookingActions.push({
id: "delete_history",
label: t("delete_history_title"),
onClick: () => {
setIsOpenDeleteHistoryDialog(true);
},
icon: "trash" as const,
color: "destructive",
});
}

let bookedActions: ActionType[] = [
{
id: "cancel",
Expand Down Expand Up @@ -347,6 +360,7 @@ function BookingListItem(booking: BookingItemProps) {
const [isOpenSetLocationDialog, setIsOpenLocationDialog] = useState(false);
const [isOpenAddGuestsDialog, setIsOpenAddGuestsDialog] = useState(false);
const [rerouteDialogIsOpen, setRerouteDialogIsOpen] = useState(false);
const [isOpenDeleteHistoryDialog, setIsOpenDeleteHistoryDialog] = useState(false);
const setLocationMutation = trpc.viewer.bookings.editLocation.useMutation({
onSuccess: () => {
showToast(t("location_updated"), "success");
Expand Down Expand Up @@ -461,6 +475,11 @@ function BookingListItem(booking: BookingItemProps) {
setIsOpenDialog={setIsOpenAddGuestsDialog}
bookingId={booking.id}
/>
<DeleteHistoryDialog
isOpenDialog={isOpenDeleteHistoryDialog}
setIsOpenDialog={setIsOpenDeleteHistoryDialog}
bookingId={booking.id}
/>
{booking.paid && booking.payment[0] && (
<ChargeCardDialog
isOpenDialog={chargeCardDialogIsOpen}
Expand Down
68 changes: 68 additions & 0 deletions apps/web/components/dialog/DeleteHistoryDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { Dispatch, SetStateAction } from "react";

import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { Button, Dialog, DialogContent, DialogFooter, DialogHeader, Icon } from "@calcom/ui";
import { showToast } from "@calcom/ui";

interface IDeleteHistoryDialog {
isOpenDialog: boolean;
setIsOpenDialog: Dispatch<SetStateAction<boolean>>;
bookingId: number;
}

const DeleteHistoryDialog = (props: IDeleteHistoryDialog) => {
const { t } = useLocale();
const { isOpenDialog, setIsOpenDialog, bookingId } = props;
const utils = trpc.useUtils();

const deleteHistoryBookingMutation = trpc.viewer.bookings.deleteHistory.useMutation({
onSuccess: async () => {
showToast(t("booking_delete_successfully"), "success");
setIsOpenDialog(false);
utils.viewer.bookings.invalidate();
},
onError: (err) => {
const message = `${err.data?.code}: ${t(err.message)}`;
showToast(message || t("unable_to_delete_booking"), "error");
},
});

const handleDelete = () => {
deleteHistoryBookingMutation.mutate({ id: bookingId });
};

return (
<Dialog open={isOpenDialog} onOpenChange={setIsOpenDialog}>
<DialogContent enableOverflow>
<div className="flex flex-row space-x-3">
<div className="bg-subtle flex h-10 w-10 flex-shrink-0 justify-center rounded-full ">
<Icon name="trash" className="m-auto h-6 w-6" />
</div>
<div className="w-full pt-1">
<DialogHeader title={t("delete_history_title")} />
<p className="text-sm font-normal">{t("delete_history_description")}</p>
<DialogFooter>
<Button
onClick={() => {
setIsOpenDialog(false);
}}
type="button"
color="secondary">
{t("cancel")}
</Button>
<Button
data-testid="delete_history"
loading={deleteHistoryBookingMutation.isPending}
onClick={handleDelete}>
{t("confirm_delete_event_type")}
</Button>
</DialogFooter>
</div>
</div>
</DialogContent>
</Dialog>
);
};

export default DeleteHistoryDialog;
1 change: 1 addition & 0 deletions apps/web/public/static/locales/ar/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -2957,4 +2957,5 @@
"verify_email": "التحقق من البريد الإلكتروني",
"verify_email_change": "تأكيد تغيير البريد الإلكتروني",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ أضف السلاسل الجديدة أعلاه هنا ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"

}
6 changes: 5 additions & 1 deletion apps/web/public/static/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -2956,5 +2956,9 @@
"desc": "Desc",
"verify_email": "Verify email",
"verify_email_change": "Verify email change",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑",
"delete_history_title": "Delete booking history",
"delete_history_description": "Are you sure you want to delete this from your booking history?",
"unable_to_delete_booking": "Unable to delete booking",
"booking_delete_successfully": "Booking deleted successfully"
}
1 change: 1 addition & 0 deletions apps/web/public/static/locales/he/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -2957,4 +2957,5 @@
"verify_email": "אימות אימייל",
"verify_email_change": "אימות שינוי כתובת דוא\"ל",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"

}
1 change: 1 addition & 0 deletions apps/web/public/static/locales/it/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -2957,4 +2957,5 @@
"verify_email": "Verifica email",
"verify_email_change": "Verifica la modifica dell'email",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Aggiungi le tue nuove stringhe qui sopra ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"

}
1 change: 1 addition & 0 deletions apps/web/public/static/locales/ja/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -2957,4 +2957,5 @@
"verify_email": "メールアドレスを確認",
"verify_email_change": "メールアドレスの変更を確認",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ この上に新しい文字列を追加してください ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"

}
21 changes: 21 additions & 0 deletions packages/trpc/server/routers/viewer/bookings/_router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import publicProcedure from "../../../procedures/publicProcedure";
import { router } from "../../../trpc";
import { ZAddGuestsInputSchema } from "./addGuests.schema";
import { ZConfirmInputSchema } from "./confirm.schema";
import { ZDeleteHistoryInputSchema } from "./deleteHistory.schema";
import { ZEditLocationInputSchema } from "./editLocation.schema";
import { ZFindInputSchema } from "./find.schema";
import { ZGetInputSchema } from "./get.schema";
Expand All @@ -16,6 +17,7 @@ type BookingsRouterHandlerCache = {
requestReschedule?: typeof import("./requestReschedule.handler").requestRescheduleHandler;
editLocation?: typeof import("./editLocation.handler").editLocationHandler;
addGuests?: typeof import("./addGuests.handler").addGuestsHandler;
deleteHistory?: typeof import("./deleteHistory.handler").deleteHistoryHandler;
confirm?: typeof import("./confirm.handler").confirmHandler;
getBookingAttendees?: typeof import("./getBookingAttendees.handler").getBookingAttendeesHandler;
find?: typeof import("./find.handler").getHandler;
Expand Down Expand Up @@ -93,6 +95,25 @@ export const bookingsRouter = router({
input,
});
}),
deleteHistory: authedProcedure.input(ZDeleteHistoryInputSchema).mutation(async ({ input, ctx }) => {
if (!UNSTABLE_HANDLER_CACHE.deleteHistory) {
// Dynamically import the deleteHistory handler
UNSTABLE_HANDLER_CACHE.deleteHistory = await import("./deleteHistory.handler").then(
(mod) => mod.deleteHistoryHandler
);
}

// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.deleteHistory) {
throw new Error("Failed to load handler");
}

// Execute the handler with the context and input
return UNSTABLE_HANDLER_CACHE.deleteHistory({
ctx,
input,
});
}),

confirm: authedProcedure.input(ZConfirmInputSchema).mutation(async ({ input, ctx }) => {
if (!UNSTABLE_HANDLER_CACHE.confirm) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { prisma } from "@calcom/prisma";

import type { TrpcSessionUser } from "../../../trpc";
import type { TDeleteInputSchema } from "./deleteHistory.schema";

type DeleteOptions = {
ctx: {
user: NonNullable<TrpcSessionUser>;
};
input: TDeleteInputSchema;
};

export const deleteHistoryHandler = async ({ ctx: _ctx, input }: DeleteOptions) => {
const { id } = input;

await prisma.booking.delete({
where: {
id,
},
});

await prisma.bookingSeat.deleteMany({
where: {
bookingId: id,
},
});

await prisma.bookingReference.deleteMany({
where: {
bookingId: id,
},
});

return {
id,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { z } from "zod";

export const ZDeleteHistoryInputSchema = z.object({
id: z.number(),
});

export type TDeleteInputSchema = z.infer<typeof ZDeleteHistoryInputSchema>;
Loading