feat: add attendee data to CSV export with seated event support (#21842)

* feat: add attendee data to CSV export with seated event support

- Add up to 3 attendees to CSV export in 'name (email)' format
- Use booking.seatsReferences for seated events, booking.attendees for regular events
- Maintain backward compatibility with existing bookerEmail/bookerName fields
- Add attendee1, attendee2, attendee3 columns to CSV output

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix: restore missing comment as requested in PR review

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* Update packages/features/insights/server/events.ts

* feat: remove duplicate booker columns from CSV export

- Remove bookerEmail and bookerName columns as they duplicate attendee data
- Remove noShowGuest field which was based on booker data
- Remove unused booker field from bookingMap
- Keep only attendee1, attendee2, attendee3 columns with name (email) format

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* feat: restore noShowGuest field to CSV export

- Add noShowGuest field mapping from first attendee's noShow property
- Maintain existing attendee1, attendee2, attendee3 columns
- Default to false when no attendees exist
- Works with both seated events and regular events

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* rename column

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: eunjae@cal.com <hey@eunjae.dev>
This commit is contained in:
devin-ai-integration[bot]
2025-06-20 08:11:08 +01:00
committed by GitHub
co-authored by eunjae@cal.com
parent 04e60611ed
commit 956fd6ae2f
+53 -8
View File
@@ -462,28 +462,73 @@ class EventsInsights {
noShow: true,
},
},
seatsReferences: {
select: {
attendee: {
select: {
name: true,
email: true,
noShow: true,
},
},
},
},
},
});
const bookingMap = new Map(bookings.map((booking) => [booking.uid, booking.attendees[0] || null]));
const bookingMap = new Map(
bookings.map((booking) => {
const attendeeList =
booking.seatsReferences.length > 0
? booking.seatsReferences.map((ref) => ref.attendee)
: booking.attendees;
const formattedAttendees = attendeeList
.slice(0, 3)
.map((attendee) => (attendee ? `${attendee.name} (${attendee.email})` : null));
return [
booking.uid,
{
noShowGuest: attendeeList[0]?.noShow || false,
attendee1: formattedAttendees[0] || null,
attendee2: formattedAttendees[1] || null,
attendee3: formattedAttendees[2] || null,
},
];
})
);
const data = csvData.map((bookingTimeStatus) => {
if (!bookingTimeStatus.uid) {
// should not be reached because we filtered above
return bookingTimeStatus;
return {
...bookingTimeStatus,
noShowGuest: false,
attendee1: null,
attendee2: null,
attendee3: null,
};
}
const booker = bookingMap.get(bookingTimeStatus.uid);
const attendeeData = bookingMap.get(bookingTimeStatus.uid);
if (!booker) {
return bookingTimeStatus;
if (!attendeeData) {
return {
...bookingTimeStatus,
noShowGuest: false,
attendee1: null,
attendee2: null,
attendee3: null,
};
}
return {
...bookingTimeStatus,
noShowGuest: booker.noShow,
bookerEmail: booker.email,
bookerName: booker.name,
noShowGuest: attendeeData.noShowGuest,
attendee1: attendeeData.attendee1,
attendee2: attendeeData.attendee2,
attendee3: attendeeData.attendee3,
};
});