-
Notifications
You must be signed in to change notification settings - Fork 7.8k
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
Fix - add team members to emails #7207
Changes from 1 commit
98cd23b
d128c3e
d05fe6f
cbdda75
3dcb5dd
5e9fda7
ff93467
24becee
b4c7145
94a6cae
8f3f17b
5a9f20b
5288fec
9035b05
97d7842
b4fb91f
25a3d97
c4c629c
7936b3a
e6dfa35
9f121ff
fe94312
8ee8d7a
e17f69e
3ecbebd
9f463dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import { TFunction } from "next-i18next"; | ||
import { cloneDeep } from "lodash"; | ||
import type { TFunction } from "next-i18next"; | ||
|
||
import type { CalendarEvent, Person } from "@calcom/types/Calendar"; | ||
|
||
|
@@ -12,8 +13,10 @@ import AttendeeScheduledEmail from "./templates/attendee-scheduled-email"; | |
import AttendeeWasRequestedToRescheduleEmail from "./templates/attendee-was-requested-to-reschedule-email"; | ||
import BrokenIntegrationEmail from "./templates/broken-integration-email"; | ||
import DisabledAppEmail from "./templates/disabled-app-email"; | ||
import FeedbackEmail, { Feedback } from "./templates/feedback-email"; | ||
import ForgotPasswordEmail, { PasswordReset } from "./templates/forgot-password-email"; | ||
import type { Feedback } from "./templates/feedback-email"; | ||
import FeedbackEmail from "./templates/feedback-email"; | ||
import type { PasswordReset } from "./templates/forgot-password-email"; | ||
import ForgotPasswordEmail from "./templates/forgot-password-email"; | ||
import OrganizerCancelledEmail from "./templates/organizer-cancelled-email"; | ||
import OrganizerLocationChangeEmail from "./templates/organizer-location-change-email"; | ||
import OrganizerPaymentRefundFailedEmail from "./templates/organizer-payment-refund-failed-email"; | ||
|
@@ -22,10 +25,12 @@ import OrganizerRequestReminderEmail from "./templates/organizer-request-reminde | |
import OrganizerRequestedToRescheduleEmail from "./templates/organizer-requested-to-reschedule-email"; | ||
import OrganizerRescheduledEmail from "./templates/organizer-rescheduled-email"; | ||
import OrganizerScheduledEmail from "./templates/organizer-scheduled-email"; | ||
import TeamInviteEmail, { TeamInvite } from "./templates/team-invite-email"; | ||
import type { TeamInvite } from "./templates/team-invite-email"; | ||
import TeamInviteEmail from "./templates/team-invite-email"; | ||
|
||
export const sendScheduledEmails = async (calEvent: CalendarEvent) => { | ||
const emailsToSend: Promise<unknown>[] = []; | ||
const clonedEvent = cloneDeep(calEvent); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we cloning it? Asking because deepClone might be a bit slow plus require lodash. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the attendee emails, we sometimes have to filter |
||
|
||
emailsToSend.push( | ||
...calEvent.attendees.map((attendee) => { | ||
|
@@ -43,14 +48,29 @@ export const sendScheduledEmails = async (calEvent: CalendarEvent) => { | |
emailsToSend.push( | ||
new Promise((resolve, reject) => { | ||
try { | ||
const scheduledEmail = new OrganizerScheduledEmail(calEvent); | ||
const scheduledEmail = new OrganizerScheduledEmail(clonedEvent); | ||
resolve(scheduledEmail.sendEmail()); | ||
} catch (e) { | ||
reject(console.error("OrganizerScheduledEmail.sendEmail failed", e)); | ||
} | ||
}) | ||
); | ||
|
||
if (clonedEvent.team) { | ||
for (const teamMember of clonedEvent.team.members) { | ||
emailsToSend.push( | ||
new Promise((resolve, reject) => { | ||
try { | ||
const scheduledEmail = new OrganizerScheduledEmail(clonedEvent, undefined, teamMember); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By passing a team member, we can extract their locale and translation for the email |
||
resolve(scheduledEmail.sendEmail()); | ||
} catch (e) { | ||
reject(console.error("OrganizerScheduledEmail.sendEmail failed", e)); | ||
} | ||
}) | ||
); | ||
} | ||
hariombalhara marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
await Promise.all(emailsToSend); | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import { TFunction } from "next-i18next"; | ||
import type { TFunction } from "next-i18next"; | ||
|
||
import type { CalendarEvent } from "@calcom/types/Calendar"; | ||
|
||
|
@@ -35,6 +35,14 @@ export function WhoInfo(props: { calEvent: CalendarEvent; t: TFunction }) { | |
email={attendee.email} | ||
/> | ||
))} | ||
{props.calEvent.team?.members.map((member) => ( | ||
joeauyeung marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<PersonInfo | ||
key={member.id || member.name} | ||
name={member.name} | ||
role={t("team_member")} | ||
email={member.email} | ||
/> | ||
))} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there are team members, loop through and display in the email |
||
</> | ||
} | ||
withSpacer | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,5 @@ | ||
import { | ||
App, | ||
BookingStatus, | ||
Credential, | ||
EventTypeCustomInput, | ||
Prisma, | ||
SchedulingType, | ||
WebhookTriggerEvents, | ||
} from "@prisma/client"; | ||
import type { App, Credential, EventTypeCustomInput, Prisma } from "@prisma/client"; | ||
import { BookingStatus, SchedulingType, WebhookTriggerEvents } from "@prisma/client"; | ||
import async from "async"; | ||
import { isValidPhoneNumber } from "libphonenumber-js"; | ||
import { cloneDeep } from "lodash"; | ||
|
@@ -16,15 +9,18 @@ import { v5 as uuidv5 } from "uuid"; | |
import z from "zod"; | ||
|
||
import { metadata as GoogleMeetMetadata } from "@calcom/app-store/googlevideo/_metadata"; | ||
import { getLocationValueForDB, LocationObject } from "@calcom/app-store/locations"; | ||
import type { LocationObject } from "@calcom/app-store/locations"; | ||
import { getLocationValueForDB } from "@calcom/app-store/locations"; | ||
import { MeetLocationType } from "@calcom/app-store/locations"; | ||
import { handleEthSignature } from "@calcom/app-store/rainbow/utils/ethereum"; | ||
import { EventTypeAppsList, getAppFromSlug, getEventTypeAppData } from "@calcom/app-store/utils"; | ||
import type { EventTypeAppsList } from "@calcom/app-store/utils"; | ||
import { getAppFromSlug, getEventTypeAppData } from "@calcom/app-store/utils"; | ||
import { cancelScheduledJobs, scheduleTrigger } from "@calcom/app-store/zapier/lib/nodeScheduler"; | ||
import EventManager from "@calcom/core/EventManager"; | ||
import { getEventName } from "@calcom/core/event"; | ||
import { getUserAvailability } from "@calcom/core/getUserAvailability"; | ||
import dayjs, { ConfigType } from "@calcom/dayjs"; | ||
import type { ConfigType } from "@calcom/dayjs"; | ||
import dayjs from "@calcom/dayjs"; | ||
import { | ||
sendAttendeeRequestEmail, | ||
sendOrganizerRequestEmail, | ||
|
@@ -55,9 +51,10 @@ import { | |
import type { BufferedBusyTime } from "@calcom/types/BufferedBusyTime"; | ||
import type { AdditionalInformation, AppsStatus, CalendarEvent } from "@calcom/types/Calendar"; | ||
import type { EventResult, PartialReference } from "@calcom/types/EventManager"; | ||
import { WorkingHours } from "@calcom/types/schedule"; | ||
import type { WorkingHours } from "@calcom/types/schedule"; | ||
|
||
import sendPayload, { EventTypeInfo } from "../../webhooks/lib/sendPayload"; | ||
import type { EventTypeInfo } from "../../webhooks/lib/sendPayload"; | ||
import sendPayload from "../../webhooks/lib/sendPayload"; | ||
|
||
const translator = short(); | ||
const log = logger.getChildLogger({ prefix: ["[api] book:user"] }); | ||
|
@@ -538,7 +535,7 @@ async function handler(req: NextApiRequest & { userId?: number | undefined }) { | |
|
||
const teamMembers = await Promise.all(teamMemberPromises); | ||
|
||
const attendeesList = [...invitee, ...guests, ...teamMembers]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is causing collective events to not add all team members to the created calendar event. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In #7756 team members are added to the I tested this locally and the db record, email, and calendar event description have the team members included. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
const attendeesList = [...invitee, ...guests]; | ||
|
||
const eventNameObject = { | ||
attendeeName: reqBody.name || "Nameless", | ||
|
@@ -720,7 +717,8 @@ async function handler(req: NextApiRequest & { userId?: number | undefined }) { | |
|
||
if (eventType.schedulingType === SchedulingType.COLLECTIVE) { | ||
evt.team = { | ||
members: users.map((user) => user.name || user.username || "Nameless"), | ||
// members: users.map((user) => user.name || user.username || "Nameless"), | ||
members: teamMembers, | ||
name: eventType.team?.name || "Nameless", | ||
}; // used for invitee emails | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we need to alter the attendee emails to hide attendees if needed. Let's clone the event to pass to the organizer emails