Files
Hariom BalharaGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
a0e5e03903 feat: Add async spam check and decoy booking response (#24326)
* feat: Add async spam check integration and decoy booking response

- Integrate SpamCheckService with handleNewBooking workflow
- Implement parallel spam check execution for minimal performance impact
- Add decoy booking response with localStorage-based success page
- Extract organization ID from event type for org-specific blocking
- Add comprehensive test coverage for spam detection scenarios
- Create reusable components for booking success cards
- Implement fail-open behavior to never block legitimate bookings

This builds on the spam blocker DI infrastructure from PR #24040 by
adding the actual integration into the booking flow and implementing
the decoy response mechanism to avoid revealing spam detection to
malicious actors.

Related: #24040
Co-Authored-By: [email protected] <[email protected]>

* Do checks in paralle

* Fix leaking host name in title

* Reduce expoiry time localstorage

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-10-14 11:36:51 +00:00

51 lines
1.7 KiB
TypeScript

"use client";
import { useParams } from "next/navigation";
import dayjs from "@calcom/dayjs";
import { DecoyBookingSuccessCard } from "@calcom/features/bookings/Booker/components/DecoyBookingSuccessCard";
import { useDecoyBooking } from "@calcom/features/bookings/Booker/components/hooks/useDecoyBooking";
export default function BookingSuccessful() {
const params = useParams();
const uid = params?.uid as string;
const bookingData = useDecoyBooking(uid);
if (!bookingData) {
return null;
}
const { booking } = bookingData;
// Format the data for the BookingSuccessCard
const startTime = booking.startTime ? dayjs(booking.startTime) : null;
const endTime = booking.endTime ? dayjs(booking.endTime) : null;
const timeZone = booking.booker?.timeZone || booking.host?.timeZone || dayjs.tz.guess();
const formattedDate = startTime ? startTime.tz(timeZone).format("dddd, MMMM D, YYYY") : "";
const formattedTime = startTime ? startTime.tz(timeZone).format("h:mm A") : "";
const formattedEndTime = endTime ? endTime.tz(timeZone).format("h:mm A") : "";
const formattedTimeZone = timeZone;
const hostName = booking.host?.name || null;
const hostEmail = null; // Email not stored for spam decoy bookings
const attendeeName = booking.booker?.name || null;
const attendeeEmail = booking.booker?.email || null;
return (
<DecoyBookingSuccessCard
title={booking.title || "Booking"}
formattedDate={formattedDate}
formattedTime={formattedTime}
endTime={formattedEndTime}
formattedTimeZone={formattedTimeZone}
hostName={hostName}
hostEmail={hostEmail}
attendeeName={attendeeName}
attendeeEmail={attendeeEmail}
location={booking.location || null}
/>
);
}