diff --git a/apps/web/components/booking/BookingListItem.tsx b/apps/web/components/booking/BookingListItem.tsx index a351f9615b5c0f..e6a53d98233f88 100644 --- a/apps/web/components/booking/BookingListItem.tsx +++ b/apps/web/components/booking/BookingListItem.tsx @@ -1,6 +1,6 @@ import type { AssignmentReason } from "@prisma/client"; import Link from "next/link"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { Controller, useFieldArray, useForm } from "react-hook-form"; import type { getEventLocationValue } from "@calcom/app-store/locations"; @@ -420,16 +420,38 @@ function BookingListItem(booking: BookingItemProps) { ]; const showPendingPayment = paymentAppData.enabled && booking.payment.length && !booking.paid; - const attendeeList = booking.attendees.map((attendee) => { - return { - name: attendee.name, - email: attendee.email, - id: attendee.id, - noShow: attendee.noShow || false, - phoneNumber: attendee.phoneNumber, - }; + + const [attendeeList, setAttendeeList] = useState( + booking.attendees.map((attendee) => { + return { + name: attendee.name, + email: attendee.email, + id: attendee.id, + noShow: attendee.noShow || false, + phoneNumber: attendee.phoneNumber, + }; + }) + ); + + const noShowMutation = trpc.viewer.markNoShow.useMutation({ + onSuccess: async (data) => { + showToast(data.message, "success"); + }, + onError: (error) => { + showToast(error.message, "error"); + }, }); + const handleNoShowChange = (email: string, noShow: boolean) => { + noShowMutation.mutate({ + bookingUid: booking.uid, + attendees: [{ email, noShow }], + }); + setAttendeeList((prev) => + prev.map((attendee) => (attendee.email === email ? { ...attendee, noShow } : attendee)) + ); + }; + return ( <> @@ -641,6 +663,7 @@ function BookingListItem(booking: BookingItemProps) { currentEmail={userEmail} bookingUid={booking.uid} isBookingInPast={isBookingInPast} + handleNoShowChange={handleNoShowChange} /> )} {isCancelled && booking.rescheduled && ( @@ -865,36 +888,16 @@ type AttendeeProps = { type NoShowProps = { bookingUid: string; isBookingInPast: boolean; + handleNoShowChange: (email: string, noShow: boolean) => void; }; const Attendee = (attendeeProps: AttendeeProps & NoShowProps) => { - const { email, name, bookingUid, isBookingInPast, noShow: noShowAttendee, phoneNumber } = attendeeProps; + const { email, name, isBookingInPast, noShow, phoneNumber, handleNoShowChange } = attendeeProps; const { t } = useLocale(); - const [noShow, setNoShow] = useState(noShowAttendee); const [openDropdown, setOpenDropdown] = useState(false); const { copyToClipboard, isCopied } = useCopy(); - const noShowMutation = trpc.viewer.markNoShow.useMutation({ - onSuccess: async (data) => { - showToast(data.message, "success"); - }, - onError: (err) => { - showToast(err.message, "error"); - }, - }); - - function toggleNoShow({ - attendee, - bookingUid, - }: { - attendee: { email: string; noShow: boolean }; - bookingUid: string; - }) { - noShowMutation.mutate({ bookingUid, attendees: [attendee] }); - setNoShow(!noShow); - } - return ( @@ -948,7 +951,7 @@ const Attendee = (attendeeProps: AttendeeProps & NoShowProps) => { onClick={(e) => { e.preventDefault(); setOpenDropdown(false); - toggleNoShow({ attendee: { noShow: false, email }, bookingUid }); + handleNoShowChange(email, false); }} StartIcon="eye"> {t("unmark_as_no_show")} @@ -959,7 +962,7 @@ const Attendee = (attendeeProps: AttendeeProps & NoShowProps) => { onClick={(e) => { e.preventDefault(); setOpenDropdown(false); - toggleNoShow({ attendee: { noShow: true, email }, bookingUid }); + handleNoShowChange(email, true); }} StartIcon="eye-off"> {t("mark_as_no_show")} @@ -974,29 +977,15 @@ const Attendee = (attendeeProps: AttendeeProps & NoShowProps) => { type GroupedAttendeeProps = { attendees: AttendeeProps[]; - bookingUid: string; + handleNoShowChange: (email: string, noShow: boolean) => void; }; const GroupedAttendees = (groupedAttendeeProps: GroupedAttendeeProps) => { - const { bookingUid } = groupedAttendeeProps; - const attendees = groupedAttendeeProps.attendees.map((attendee) => { - return { - id: attendee.id, - email: attendee.email, - name: attendee.name, - noShow: attendee.noShow || false, - }; - }); + const { attendees, handleNoShowChange } = groupedAttendeeProps; + const { t } = useLocale(); - const noShowMutation = trpc.viewer.markNoShow.useMutation({ - onSuccess: async (data) => { - showToast(t(data.message), "success"); - }, - onError: (err) => { - showToast(err.message, "error"); - }, - }); - const { control, handleSubmit } = useForm<{ + + const { control, handleSubmit, reset } = useForm<{ attendees: AttendeeProps[]; }>({ defaultValues: { @@ -1010,9 +999,17 @@ const GroupedAttendees = (groupedAttendeeProps: GroupedAttendeeProps) => { name: "attendees", }); + useEffect(() => { + reset({ + attendees, + }); + }, [attendees, reset]); + const onSubmit = (data: { attendees: AttendeeProps[] }) => { const filteredData = data.attendees.slice(1); - noShowMutation.mutate({ bookingUid, attendees: filteredData }); + for (const attendee of filteredData) { + handleNoShowChange(attendee.email, attendee.noShow); + } setOpenDropdown(false); }; @@ -1074,50 +1071,24 @@ const NoShowAttendeesDialog = ({ attendees, isOpen, setIsOpen, - bookingUid, + handleNoShowChange, }: { attendees: AttendeeProps[]; isOpen: boolean; setIsOpen: (value: boolean) => void; - bookingUid: string; + handleNoShowChange: (email: string, noShow: boolean) => void; }) => { const { t } = useLocale(); - const [noShowAttendees, setNoShowAttendees] = useState( - attendees.map((attendee) => ({ - id: attendee.id, - email: attendee.email, - name: attendee.name, - noShow: attendee.noShow || false, - })) - ); - - const noShowMutation = trpc.viewer.markNoShow.useMutation({ - onSuccess: async (data) => { - const newValue = data.attendees[0]; - setNoShowAttendees((old) => - old.map((attendee) => - attendee.email === newValue.email ? { ...attendee, noShow: newValue.noShow } : attendee - ) - ); - showToast(t(data.message), "success"); - }, - onError: (err) => { - showToast(err.message, "error"); - }, - }); return ( setIsOpen(false)}> - {noShowAttendees.map((attendee) => ( + {attendees.map((attendee) => (
{ e.preventDefault(); - noShowMutation.mutate({ - bookingUid, - attendees: [{ email: attendee.email, noShow: !attendee.noShow }], - }); + handleNoShowChange(attendee.email, !attendee.noShow); }}>
@@ -1208,12 +1179,14 @@ const DisplayAttendees = ({ currentEmail, bookingUid, isBookingInPast, + handleNoShowChange, }: { attendees: AttendeeProps[]; user: UserProps | null; currentEmail?: string | null; bookingUid: string; isBookingInPast: boolean; + handleNoShowChange: (email: string, noShow: boolean) => void; }) => { const { t } = useLocale(); attendees.sort((a, b) => a.id - b.id); @@ -1222,7 +1195,12 @@ const DisplayAttendees = ({
{user && } {attendees.length > 1 ? :  {t("and")} } - + {attendees.length > 1 && ( <>
 {t("and")} 
@@ -1230,17 +1208,27 @@ const DisplayAttendees = ({ (

- +

))}> {isBookingInPast ? ( - + ) : ( )}
) : ( - + )} )}