Wrong language in emails (#1541)
* test --wip * --wip * --wip * --wip * split language into organizer-attendees * name fix for tAttendees * --WIP * added attendee locale migration, --WIP * --wip * fixed check types --wip * updated person language type * test snapshot updated * --wip * --WIP * --WIP * --WIP * test changes revert * cleanup * removed extra space from test Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									1119d7f558
								
							
						
					
					
						commit
						af89de8004
					
				
					 26 changed files with 324 additions and 221 deletions
				
			
		|  | @ -10,7 +10,6 @@ import { getErrorFromUnknown } from "@lib/errors"; | ||||||
| import EventManager from "@lib/events/EventManager"; | import EventManager from "@lib/events/EventManager"; | ||||||
| import { CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar"; | import { CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar"; | ||||||
| import prisma from "@lib/prisma"; | import prisma from "@lib/prisma"; | ||||||
| import { Ensure } from "@lib/types/utils"; |  | ||||||
| 
 | 
 | ||||||
| import { getTranslation } from "@server/lib/i18n"; | import { getTranslation } from "@server/lib/i18n"; | ||||||
| 
 | 
 | ||||||
|  | @ -78,18 +77,35 @@ async function handlePaymentSuccess(event: Stripe.Event) { | ||||||
|   if (!user) throw new Error("No user found"); |   if (!user) throw new Error("No user found"); | ||||||
| 
 | 
 | ||||||
|   const t = await getTranslation(user.locale ?? "en", "common"); |   const t = await getTranslation(user.locale ?? "en", "common"); | ||||||
|  |   const attendeesListPromises = booking.attendees.map(async (attendee) => { | ||||||
|  |     return { | ||||||
|  |       name: attendee.name, | ||||||
|  |       email: attendee.email, | ||||||
|  |       timeZone: attendee.timeZone, | ||||||
|  |       language: { | ||||||
|  |         translate: await getTranslation(attendee.locale ?? "en", "common"), | ||||||
|  |         locale: attendee.locale ?? "en", | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |   }); | ||||||
| 
 | 
 | ||||||
|   const evt: Ensure<CalendarEvent, "language"> = { |   const attendeesList = await Promise.all(attendeesListPromises); | ||||||
|  | 
 | ||||||
|  |   const evt: CalendarEvent = { | ||||||
|     type: booking.title, |     type: booking.title, | ||||||
|     title: booking.title, |     title: booking.title, | ||||||
|     description: booking.description || undefined, |     description: booking.description || undefined, | ||||||
|     startTime: booking.startTime.toISOString(), |     startTime: booking.startTime.toISOString(), | ||||||
|     endTime: booking.endTime.toISOString(), |     endTime: booking.endTime.toISOString(), | ||||||
|     organizer: { email: user.email!, name: user.name!, timeZone: user.timeZone }, |     organizer: { | ||||||
|     attendees: booking.attendees, |       email: user.email!, | ||||||
|  |       name: user.name!, | ||||||
|  |       timeZone: user.timeZone, | ||||||
|  |       language: { translate: t, locale: user.locale ?? "en" }, | ||||||
|  |     }, | ||||||
|  |     attendees: attendeesList, | ||||||
|     uid: booking.uid, |     uid: booking.uid, | ||||||
|     destinationCalendar: booking.destinationCalendar || user.destinationCalendar, |     destinationCalendar: booking.destinationCalendar || user.destinationCalendar, | ||||||
|     language: t, |  | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   if (booking.location) evt.location = booking.location; |   if (booking.location) evt.location = booking.location; | ||||||
|  |  | ||||||
|  | @ -13,14 +13,14 @@ const translator = short(); | ||||||
| 
 | 
 | ||||||
| export const getWhat = (calEvent: CalendarEvent) => { | export const getWhat = (calEvent: CalendarEvent) => { | ||||||
|   return ` |   return ` | ||||||
| ${calEvent.language("what")}: | ${calEvent.organizer.language.translate("what")}: | ||||||
| ${calEvent.type} | ${calEvent.type} | ||||||
|   `;
 |   `;
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const getWhen = (calEvent: CalendarEvent) => { | export const getWhen = (calEvent: CalendarEvent) => { | ||||||
|   return ` |   return ` | ||||||
| ${calEvent.language("invitee_timezone")}: | ${calEvent.organizer.language.translate("invitee_timezone")}: | ||||||
| ${calEvent.attendees[0].timeZone} | ${calEvent.attendees[0].timeZone} | ||||||
|   `;
 |   `;
 | ||||||
| }; | }; | ||||||
|  | @ -29,26 +29,26 @@ export const getWho = (calEvent: CalendarEvent) => { | ||||||
|   const attendees = calEvent.attendees |   const attendees = calEvent.attendees | ||||||
|     .map((attendee) => { |     .map((attendee) => { | ||||||
|       return ` |       return ` | ||||||
| ${attendee?.name || calEvent.language("guest")} | ${attendee?.name || calEvent.organizer.language.translate("guest")} | ||||||
| ${attendee.email} | ${attendee.email} | ||||||
|       `;
 |       `;
 | ||||||
|     }) |     }) | ||||||
|     .join(""); |     .join(""); | ||||||
| 
 | 
 | ||||||
|   const organizer = ` |   const organizer = ` | ||||||
| ${calEvent.organizer.name} - ${calEvent.language("organizer")} | ${calEvent.organizer.name} - ${calEvent.organizer.language.translate("organizer")} | ||||||
| ${calEvent.organizer.email} | ${calEvent.organizer.email} | ||||||
|   `;
 |   `;
 | ||||||
| 
 | 
 | ||||||
|   return ` |   return ` | ||||||
| ${calEvent.language("who")}: | ${calEvent.organizer.language.translate("who")}: | ||||||
| ${organizer + attendees} | ${organizer + attendees} | ||||||
|   `;
 |   `;
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const getAdditionalNotes = (calEvent: CalendarEvent) => { | export const getAdditionalNotes = (calEvent: CalendarEvent) => { | ||||||
|   return ` |   return ` | ||||||
| ${calEvent.language("additional_notes")}: | ${calEvent.organizer.language.translate("additional_notes")}: | ||||||
| ${calEvent.description} | ${calEvent.description} | ||||||
|   `;
 |   `;
 | ||||||
| }; | }; | ||||||
|  | @ -74,7 +74,7 @@ export const getLocation = (calEvent: CalendarEvent) => { | ||||||
| 
 | 
 | ||||||
| export const getManageLink = (calEvent: CalendarEvent) => { | export const getManageLink = (calEvent: CalendarEvent) => { | ||||||
|   return ` |   return ` | ||||||
| ${calEvent.language("need_to_reschedule_or_cancel")} | ${calEvent.organizer.language.translate("need_to_reschedule_or_cancel")} | ||||||
| ${getCancelLink(calEvent)} | ${getCancelLink(calEvent)} | ||||||
|   `;
 |   `;
 | ||||||
| }; | }; | ||||||
|  | @ -96,7 +96,7 @@ export const getRichDescription = (calEvent: CalendarEvent, attendee?: Person) = | ||||||
| ${getWhat(calEvent)} | ${getWhat(calEvent)} | ||||||
| ${getWhen(calEvent)} | ${getWhen(calEvent)} | ||||||
| ${getWho(calEvent)} | ${getWho(calEvent)} | ||||||
| ${calEvent.language("where")}: | ${calEvent.organizer.language.translate("where")}: | ||||||
| ${getLocation(calEvent)} | ${getLocation(calEvent)} | ||||||
| ${getAdditionalNotes(calEvent)} | ${getAdditionalNotes(calEvent)} | ||||||
|   `.trim();
 |   `.trim();
 | ||||||
|  | @ -106,7 +106,7 @@ ${getAdditionalNotes(calEvent)} | ||||||
| ${getWhat(calEvent)} | ${getWhat(calEvent)} | ||||||
| ${getWhen(calEvent)} | ${getWhen(calEvent)} | ||||||
| ${getWho(calEvent)} | ${getWho(calEvent)} | ||||||
| ${calEvent.language("where")}: | ${calEvent.organizer.language.translate("where")}: | ||||||
| ${getLocation(calEvent)} | ${getLocation(calEvent)} | ||||||
| ${getAdditionalNotes(calEvent)} | ${getAdditionalNotes(calEvent)} | ||||||
| ${getManageLink(calEvent)} | ${getManageLink(calEvent)} | ||||||
|  |  | ||||||
|  | @ -25,14 +25,14 @@ export default class AttendeeAwaitingPaymentEmail extends AttendeeScheduledEmail | ||||||
|       to: `${this.attendee.name} <${this.attendee.email}>`, |       to: `${this.attendee.name} <${this.attendee.email}>`, | ||||||
|       from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, |       from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, | ||||||
|       replyTo: this.calEvent.organizer.email, |       replyTo: this.calEvent.organizer.email, | ||||||
|       subject: `${this.calEvent.language("awaiting_payment_subject", { |       subject: `${this.calEvent.attendees[0].language.translate("awaiting_payment_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.team?.name || this.calEvent.organizer.name, |         name: this.calEvent.team?.name || this.calEvent.organizer.name, | ||||||
|         date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( |         date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|           this.getInviteeStart().format("dddd").toLowerCase() |           this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|           this.getInviteeStart().format("MMMM").toLowerCase() |           this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 |         )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -43,8 +43,8 @@ export default class AttendeeAwaitingPaymentEmail extends AttendeeScheduledEmail | ||||||
| 
 | 
 | ||||||
|   protected getTextBody(): string { |   protected getTextBody(): string { | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("meeting_awaiting_payment")} | ${this.calEvent.attendees[0].language.translate("meeting_awaiting_payment")} | ||||||
| ${this.calEvent.language("emailed_you_and_any_other_attendees")} | ${this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees")} | ||||||
| ${this.getWhat()} | ${this.getWhat()} | ||||||
| ${this.getWhen()} | ${this.getWhen()} | ||||||
| ${this.getLocation()} | ${this.getLocation()} | ||||||
|  | @ -53,14 +53,14 @@ ${this.getAdditionalNotes()} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("awaiting_payment_subject", { |     const headerContent = this.calEvent.attendees[0].language.translate("awaiting_payment_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.team?.name || this.calEvent.organizer.name, |       name: this.calEvent.team?.name || this.calEvent.organizer.name, | ||||||
|       date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( |       date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("dddd").toLowerCase() |         this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("MMMM").toLowerCase() |         this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 |       )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -73,8 +73,8 @@ ${this.getAdditionalNotes()} | ||||||
|       <div style="background-color:#F5F5F5;"> |       <div style="background-color:#F5F5F5;"> | ||||||
|         ${emailSchedulingBodyHeader("calendarCircle")} |         ${emailSchedulingBodyHeader("calendarCircle")} | ||||||
|         ${emailScheduledBodyHeaderContent( |         ${emailScheduledBodyHeaderContent( | ||||||
|           this.calEvent.language("meeting_awaiting_payment"), |           this.calEvent.attendees[0].language.translate("meeting_awaiting_payment"), | ||||||
|           this.calEvent.language("emailed_you_and_any_other_attendees") |           this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees") | ||||||
|         )} |         )} | ||||||
|         ${emailSchedulingBodyDivider()} |         ${emailSchedulingBodyDivider()} | ||||||
|         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> |         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> | ||||||
|  | @ -148,7 +148,7 @@ ${this.getAdditionalNotes()} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getManageLink(): string { |   protected getManageLink(): string { | ||||||
|     const manageText = this.calEvent.language("pay_now"); |     const manageText = this.calEvent.attendees[0].language.translate("pay_now"); | ||||||
| 
 | 
 | ||||||
|     if (this.calEvent.paymentInfo) { |     if (this.calEvent.paymentInfo) { | ||||||
|       return ` |       return ` | ||||||
|  |  | ||||||
|  | @ -24,14 +24,14 @@ export default class AttendeeCancelledEmail extends AttendeeScheduledEmail { | ||||||
|       to: `${this.attendee.name} <${this.attendee.email}>`, |       to: `${this.attendee.name} <${this.attendee.email}>`, | ||||||
|       from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, |       from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, | ||||||
|       replyTo: this.calEvent.organizer.email, |       replyTo: this.calEvent.organizer.email, | ||||||
|       subject: `${this.calEvent.language("event_cancelled_subject", { |       subject: `${this.calEvent.attendees[0].language.translate("event_cancelled_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.team?.name || this.calEvent.organizer.name, |         name: this.calEvent.team?.name || this.calEvent.organizer.name, | ||||||
|         date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( |         date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|           this.getInviteeStart().format("dddd").toLowerCase() |           this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|           this.getInviteeStart().format("MMMM").toLowerCase() |           this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 |         )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -42,8 +42,8 @@ export default class AttendeeCancelledEmail extends AttendeeScheduledEmail { | ||||||
| 
 | 
 | ||||||
|   protected getTextBody(): string { |   protected getTextBody(): string { | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("event_request_cancelled")} | ${this.calEvent.attendees[0].language.translate("event_request_cancelled")} | ||||||
| ${this.calEvent.language("emailed_you_and_any_other_attendees")} | ${this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees")} | ||||||
| ${this.getWhat()} | ${this.getWhat()} | ||||||
| ${this.getWhen()} | ${this.getWhen()} | ||||||
| ${this.getLocation()} | ${this.getLocation()} | ||||||
|  | @ -52,14 +52,14 @@ ${this.getAdditionalNotes()} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("event_cancelled_subject", { |     const headerContent = this.calEvent.attendees[0].language.translate("event_cancelled_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.team?.name || this.calEvent.organizer.name, |       name: this.calEvent.team?.name || this.calEvent.organizer.name, | ||||||
|       date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( |       date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("dddd").toLowerCase() |         this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("MMMM").toLowerCase() |         this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 |       )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -73,8 +73,8 @@ ${this.getAdditionalNotes()} | ||||||
|       <div style="background-color:#F5F5F5;"> |       <div style="background-color:#F5F5F5;"> | ||||||
|         ${emailSchedulingBodyHeader("xCircle")} |         ${emailSchedulingBodyHeader("xCircle")} | ||||||
|         ${emailScheduledBodyHeaderContent( |         ${emailScheduledBodyHeaderContent( | ||||||
|           this.calEvent.language("event_request_cancelled"), |           this.calEvent.attendees[0].language.translate("event_request_cancelled"), | ||||||
|           this.calEvent.language("emailed_you_and_any_other_attendees") |           this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees") | ||||||
|         )} |         )} | ||||||
|         ${emailSchedulingBodyDivider()} |         ${emailSchedulingBodyDivider()} | ||||||
|         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> |         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> | ||||||
|  |  | ||||||
|  | @ -24,14 +24,14 @@ export default class AttendeeDeclinedEmail extends AttendeeScheduledEmail { | ||||||
|       to: `${this.attendee.name} <${this.attendee.email}>`, |       to: `${this.attendee.name} <${this.attendee.email}>`, | ||||||
|       from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, |       from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, | ||||||
|       replyTo: this.calEvent.organizer.email, |       replyTo: this.calEvent.organizer.email, | ||||||
|       subject: `${this.calEvent.language("event_declined_subject", { |       subject: `${this.calEvent.attendees[0].language.translate("event_declined_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.team?.name || this.calEvent.organizer.name, |         name: this.calEvent.team?.name || this.calEvent.organizer.name, | ||||||
|         date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( |         date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|           this.getInviteeStart().format("dddd").toLowerCase() |           this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|           this.getInviteeStart().format("MMMM").toLowerCase() |           this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 |         )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -42,8 +42,8 @@ export default class AttendeeDeclinedEmail extends AttendeeScheduledEmail { | ||||||
| 
 | 
 | ||||||
|   protected getTextBody(): string { |   protected getTextBody(): string { | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("event_request_declined")} | ${this.calEvent.attendees[0].language.translate("event_request_declined")} | ||||||
| ${this.calEvent.language("emailed_you_and_any_other_attendees")} | ${this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees")} | ||||||
| ${this.getWhat()} | ${this.getWhat()} | ||||||
| ${this.getWhen()} | ${this.getWhen()} | ||||||
| ${this.getLocation()} | ${this.getLocation()} | ||||||
|  | @ -52,14 +52,14 @@ ${this.getAdditionalNotes()} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("event_declined_subject", { |     const headerContent = this.calEvent.attendees[0].language.translate("event_declined_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.team?.name || this.calEvent.organizer.name, |       name: this.calEvent.team?.name || this.calEvent.organizer.name, | ||||||
|       date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( |       date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("dddd").toLowerCase() |         this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("MMMM").toLowerCase() |         this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 |       )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -73,8 +73,8 @@ ${this.getAdditionalNotes()} | ||||||
|       <div style="background-color:#F5F5F5;"> |       <div style="background-color:#F5F5F5;"> | ||||||
|         ${emailSchedulingBodyHeader("xCircle")} |         ${emailSchedulingBodyHeader("xCircle")} | ||||||
|         ${emailScheduledBodyHeaderContent( |         ${emailScheduledBodyHeaderContent( | ||||||
|           this.calEvent.language("event_request_declined"), |           this.calEvent.attendees[0].language.translate("event_request_declined"), | ||||||
|           this.calEvent.language("emailed_you_and_any_other_attendees") |           this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees") | ||||||
|         )} |         )} | ||||||
|         ${emailSchedulingBodyDivider()} |         ${emailSchedulingBodyDivider()} | ||||||
|         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> |         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> | ||||||
|  |  | ||||||
|  | @ -30,14 +30,14 @@ export default class AttendeeRescheduledEmail extends AttendeeScheduledEmail { | ||||||
|       to: `${this.attendee.name} <${this.attendee.email}>`, |       to: `${this.attendee.name} <${this.attendee.email}>`, | ||||||
|       from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, |       from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, | ||||||
|       replyTo: this.calEvent.organizer.email, |       replyTo: this.calEvent.organizer.email, | ||||||
|       subject: `${this.calEvent.language("rescheduled_event_type_subject", { |       subject: `${this.calEvent.attendees[0].language.translate("rescheduled_event_type_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.team?.name || this.calEvent.organizer.name, |         name: this.calEvent.team?.name || this.calEvent.organizer.name, | ||||||
|         date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( |         date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|           this.getInviteeStart().format("dddd").toLowerCase() |           this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|           this.getInviteeStart().format("MMMM").toLowerCase() |           this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 |         )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -51,20 +51,20 @@ export default class AttendeeRescheduledEmail extends AttendeeScheduledEmail { | ||||||
|     // Guests cannot
 |     // Guests cannot
 | ||||||
|     if (this.attendee === this.calEvent.attendees[0]) { |     if (this.attendee === this.calEvent.attendees[0]) { | ||||||
|       return ` |       return ` | ||||||
|   ${this.calEvent.language("event_has_been_rescheduled")} |   ${this.calEvent.attendees[0].language.translate("event_has_been_rescheduled")} | ||||||
|   ${this.calEvent.language("emailed_you_and_any_other_attendees")} |   ${this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees")} | ||||||
|   ${this.getWhat()} |   ${this.getWhat()} | ||||||
|   ${this.getWhen()} |   ${this.getWhen()} | ||||||
|   ${this.getLocation()} |   ${this.getLocation()} | ||||||
|   ${this.getAdditionalNotes()} |   ${this.getAdditionalNotes()} | ||||||
|   ${this.calEvent.language("need_to_reschedule_or_cancel")} |   ${this.calEvent.attendees[0].language.translate("need_to_reschedule_or_cancel")} | ||||||
|   ${getCancelLink(this.calEvent)} |   ${getCancelLink(this.calEvent)} | ||||||
|   `.replace(/(<([^>]+)>)/gi, "");
 |   `.replace(/(<([^>]+)>)/gi, "");
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("event_has_been_rescheduled")} | ${this.calEvent.attendees[0].language.translate("event_has_been_rescheduled")} | ||||||
| ${this.calEvent.language("emailed_you_and_any_other_attendees")} | ${this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees")} | ||||||
| ${this.getWhat()} | ${this.getWhat()} | ||||||
| ${this.getWhen()} | ${this.getWhen()} | ||||||
| ${this.getLocation()} | ${this.getLocation()} | ||||||
|  | @ -73,14 +73,14 @@ ${this.getAdditionalNotes()} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("rescheduled_event_type_subject", { |     const headerContent = this.calEvent.attendees[0].language.translate("rescheduled_event_type_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.team?.name || this.calEvent.organizer.name, |       name: this.calEvent.team?.name || this.calEvent.organizer.name, | ||||||
|       date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( |       date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("dddd").toLowerCase() |         this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("MMMM").toLowerCase() |         this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 |       )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -93,8 +93,8 @@ ${this.getAdditionalNotes()} | ||||||
|       <div style="background-color:#F5F5F5;"> |       <div style="background-color:#F5F5F5;"> | ||||||
|         ${emailSchedulingBodyHeader("calendarCircle")} |         ${emailSchedulingBodyHeader("calendarCircle")} | ||||||
|         ${emailScheduledBodyHeaderContent( |         ${emailScheduledBodyHeaderContent( | ||||||
|           this.calEvent.language("event_has_been_rescheduled"), |           this.calEvent.attendees[0].language.translate("event_has_been_rescheduled"), | ||||||
|           this.calEvent.language("emailed_you_and_any_other_attendees") |           this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees") | ||||||
|         )} |         )} | ||||||
|         ${emailSchedulingBodyDivider()} |         ${emailSchedulingBodyDivider()} | ||||||
|         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> |         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> | ||||||
|  |  | ||||||
|  | @ -61,7 +61,7 @@ export default class AttendeeScheduledEmail { | ||||||
|         .map((v, i) => (i === 1 ? v + 1 : v)) as DateArray, |         .map((v, i) => (i === 1 ? v + 1 : v)) as DateArray, | ||||||
|       startInputType: "utc", |       startInputType: "utc", | ||||||
|       productId: "calendso/ics", |       productId: "calendso/ics", | ||||||
|       title: this.calEvent.language("ics_event_title", { |       title: this.calEvent.attendees[0].language.translate("ics_event_title", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.attendees[0].name, |         name: this.calEvent.attendees[0].name, | ||||||
|       }), |       }), | ||||||
|  | @ -89,14 +89,14 @@ export default class AttendeeScheduledEmail { | ||||||
|       to: `${this.attendee.name} <${this.attendee.email}>`, |       to: `${this.attendee.name} <${this.attendee.email}>`, | ||||||
|       from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, |       from: `${this.calEvent.organizer.name} <${this.getMailerOptions().from}>`, | ||||||
|       replyTo: this.calEvent.organizer.email, |       replyTo: this.calEvent.organizer.email, | ||||||
|       subject: `${this.calEvent.language("confirmed_event_type_subject", { |       subject: `${this.calEvent.attendees[0].language.translate("confirmed_event_type_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.team?.name || this.calEvent.organizer.name, |         name: this.calEvent.team?.name || this.calEvent.organizer.name, | ||||||
|         date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( |         date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|           this.getInviteeStart().format("dddd").toLowerCase() |           this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|           this.getInviteeStart().format("MMMM").toLowerCase() |           this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 |         )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -114,8 +114,8 @@ export default class AttendeeScheduledEmail { | ||||||
| 
 | 
 | ||||||
|   protected getTextBody(): string { |   protected getTextBody(): string { | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("your_event_has_been_scheduled")} | ${this.calEvent.attendees[0].language.translate("your_event_has_been_scheduled")} | ||||||
| ${this.calEvent.language("emailed_you_and_any_other_attendees")} | ${this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees")} | ||||||
| 
 | 
 | ||||||
| ${getRichDescription(this.calEvent)} | ${getRichDescription(this.calEvent)} | ||||||
| `.trim();
 | `.trim();
 | ||||||
|  | @ -126,14 +126,14 @@ ${getRichDescription(this.calEvent)} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("confirmed_event_type_subject", { |     const headerContent = this.calEvent.attendees[0].language.translate("confirmed_event_type_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.team?.name || this.calEvent.organizer.name, |       name: this.calEvent.team?.name || this.calEvent.organizer.name, | ||||||
|       date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( |       date: `${this.getInviteeStart().format("h:mma")} - ${this.getInviteeEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("dddd").toLowerCase() |         this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("MMMM").toLowerCase() |         this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 |       )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -146,8 +146,8 @@ ${getRichDescription(this.calEvent)} | ||||||
|       <div style="background-color:#F5F5F5;"> |       <div style="background-color:#F5F5F5;"> | ||||||
|         ${emailSchedulingBodyHeader("checkCircle")} |         ${emailSchedulingBodyHeader("checkCircle")} | ||||||
|         ${emailScheduledBodyHeaderContent( |         ${emailScheduledBodyHeaderContent( | ||||||
|           this.calEvent.language("your_event_has_been_scheduled"), |           this.calEvent.attendees[0].language.translate("your_event_has_been_scheduled"), | ||||||
|           this.calEvent.language("emailed_you_and_any_other_attendees") |           this.calEvent.attendees[0].language.translate("emailed_you_and_any_other_attendees") | ||||||
|         )} |         )} | ||||||
|         ${emailSchedulingBodyDivider()} |         ${emailSchedulingBodyDivider()} | ||||||
|         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> |         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> | ||||||
|  | @ -219,8 +219,8 @@ ${getRichDescription(this.calEvent)} | ||||||
|     // Only the original attendee can make changes to the event
 |     // Only the original attendee can make changes to the event
 | ||||||
|     // Guests cannot
 |     // Guests cannot
 | ||||||
|     if (this.attendee === this.calEvent.attendees[0]) { |     if (this.attendee === this.calEvent.attendees[0]) { | ||||||
|       const manageText = this.calEvent.language("manage_this_event"); |       const manageText = this.calEvent.attendees[0].language.translate("manage_this_event"); | ||||||
|       return `<p>${this.calEvent.language( |       return `<p>${this.calEvent.attendees[0].language.translate( | ||||||
|         "need_to_reschedule_or_cancel" |         "need_to_reschedule_or_cancel" | ||||||
|       )}</p><p style="font-weight: 400; line-height: 24px;"><a href="${getCancelLink( |       )}</p><p style="font-weight: 400; line-height: 24px;"><a href="${getCancelLink( | ||||||
|         this.calEvent |         this.calEvent | ||||||
|  | @ -233,7 +233,7 @@ ${getRichDescription(this.calEvent)} | ||||||
|   protected getWhat(): string { |   protected getWhat(): string { | ||||||
|     return ` |     return ` | ||||||
|     <div style="line-height: 6px;"> |     <div style="line-height: 6px;"> | ||||||
|       <p style="color: #494949;">${this.calEvent.language("what")}</p> |       <p style="color: #494949;">${this.calEvent.attendees[0].language.translate("what")}</p> | ||||||
|       <p style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.type}</p> |       <p style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.type}</p> | ||||||
|     </div>`;
 |     </div>`;
 | ||||||
|   } |   } | ||||||
|  | @ -242,11 +242,11 @@ ${getRichDescription(this.calEvent)} | ||||||
|     return ` |     return ` | ||||||
|     <p style="height: 6px"></p> |     <p style="height: 6px"></p> | ||||||
|     <div style="line-height: 6px;"> |     <div style="line-height: 6px;"> | ||||||
|       <p style="color: #494949;">${this.calEvent.language("when")}</p> |       <p style="color: #494949;">${this.calEvent.attendees[0].language.translate("when")}</p> | ||||||
|       <p style="color: #494949; font-weight: 400; line-height: 24px;"> |       <p style="color: #494949; font-weight: 400; line-height: 24px;"> | ||||||
|       ${this.calEvent.language( |       ${this.calEvent.attendees[0].language.translate( | ||||||
|         this.getInviteeStart().format("dddd").toLowerCase() |         this.getInviteeStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.attendees[0].language.translate( | ||||||
|       this.getInviteeStart().format("MMMM").toLowerCase() |       this.getInviteeStart().format("MMMM").toLowerCase() | ||||||
|     )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format( |     )} ${this.getInviteeStart().format("D")}, ${this.getInviteeStart().format( | ||||||
|       "YYYY" |       "YYYY" | ||||||
|  | @ -261,7 +261,7 @@ ${getRichDescription(this.calEvent)} | ||||||
|     const attendees = this.calEvent.attendees |     const attendees = this.calEvent.attendees | ||||||
|       .map((attendee) => { |       .map((attendee) => { | ||||||
|         return `<div style="color: #494949; font-weight: 400; line-height: 24px;">${ |         return `<div style="color: #494949; font-weight: 400; line-height: 24px;">${ | ||||||
|           attendee?.name || `${this.calEvent.language("guest")}` |           attendee?.name || `${this.calEvent.attendees[0].language.translate("guest")}` | ||||||
|         } <span style="color: #888888"><a href="mailto:${attendee.email}" style="color: #888888;">${ |         } <span style="color: #888888"><a href="mailto:${attendee.email}" style="color: #888888;">${ | ||||||
|           attendee.email |           attendee.email | ||||||
|         }</a></span></div>`;
 |         }</a></span></div>`;
 | ||||||
|  | @ -270,14 +270,16 @@ ${getRichDescription(this.calEvent)} | ||||||
| 
 | 
 | ||||||
|     const organizer = `<div style="color: #494949; font-weight: 400; line-height: 24px;">${ |     const organizer = `<div style="color: #494949; font-weight: 400; line-height: 24px;">${ | ||||||
|       this.calEvent.organizer.name |       this.calEvent.organizer.name | ||||||
|     } - ${this.calEvent.language("organizer")} <span style="color: #888888"><a href="mailto:${ |     } - ${this.calEvent.attendees[0].language.translate( | ||||||
|  |       "organizer" | ||||||
|  |     )} <span style="color: #888888"><a href="mailto:${ | ||||||
|       this.calEvent.organizer.email |       this.calEvent.organizer.email | ||||||
|     }" style="color: #888888;">${this.calEvent.organizer.email}</a></span></div>`;
 |     }" style="color: #888888;">${this.calEvent.organizer.email}</a></span></div>`;
 | ||||||
| 
 | 
 | ||||||
|     return ` |     return ` | ||||||
|     <p style="height: 6px"></p> |     <p style="height: 6px"></p> | ||||||
|     <div style="line-height: 6px;"> |     <div style="line-height: 6px;"> | ||||||
|       <p style="color: #494949;">${this.calEvent.language("who")}</p> |       <p style="color: #494949;">${this.calEvent.attendees[0].language.translate("who")}</p> | ||||||
|       ${organizer + attendees} |       ${organizer + attendees} | ||||||
|     </div>`;
 |     </div>`;
 | ||||||
|   } |   } | ||||||
|  | @ -286,7 +288,7 @@ ${getRichDescription(this.calEvent)} | ||||||
|     return ` |     return ` | ||||||
|     <p style="height: 6px"></p> |     <p style="height: 6px"></p> | ||||||
|     <div style="line-height: 6px;"> |     <div style="line-height: 6px;"> | ||||||
|       <p style="color: #494949;">${this.calEvent.language("additional_notes")}</p> |       <p style="color: #494949;">${this.calEvent.attendees[0].language.translate("additional_notes")}</p> | ||||||
|       <p style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.description}</p> |       <p style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.description}</p> | ||||||
|     </div> |     </div> | ||||||
|     `;
 |     `;
 | ||||||
|  | @ -308,30 +310,30 @@ ${getRichDescription(this.calEvent)} | ||||||
|       return ` |       return ` | ||||||
|       <p style="height: 6px"></p> |       <p style="height: 6px"></p> | ||||||
|       <div style="line-height: 6px;"> |       <div style="line-height: 6px;"> | ||||||
|         <p style="color: #494949;">${this.calEvent.language("where")}</p> |         <p style="color: #494949;">${this.calEvent.attendees[0].language.translate("where")}</p> | ||||||
|         <p style="color: #494949; font-weight: 400; line-height: 24px;">${providerName} ${ |         <p style="color: #494949; font-weight: 400; line-height: 24px;">${providerName} ${ | ||||||
|         meetingUrl && |         meetingUrl && | ||||||
|         `<a href="${meetingUrl}" target="_blank" alt="${this.calEvent.language( |         `<a href="${meetingUrl}" target="_blank" alt="${this.calEvent.attendees[0].language.translate( | ||||||
|           "meeting_url" |           "meeting_url" | ||||||
|         )}"><img src="${linkIcon()}" width="12px"></img></a>` |         )}"><img src="${linkIcon()}" width="12px"></img></a>` | ||||||
|       }</p> |       }</p> | ||||||
|         ${ |         ${ | ||||||
|           meetingId && |           meetingId && | ||||||
|           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.language( |           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.attendees[0].language.translate( | ||||||
|             "meeting_id" |             "meeting_id" | ||||||
|           )}: <span>${meetingId}</span></div>` |           )}: <span>${meetingId}</span></div>` | ||||||
|         } |         } | ||||||
|         ${ |         ${ | ||||||
|           meetingPassword && |           meetingPassword && | ||||||
|           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.language( |           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.attendees[0].language.translate( | ||||||
|             "meeting_password" |             "meeting_password" | ||||||
|           )}: <span>${meetingPassword}</span></div>` |           )}: <span>${meetingPassword}</span></div>` | ||||||
|         } |         } | ||||||
|         ${ |         ${ | ||||||
|           meetingUrl && |           meetingUrl && | ||||||
|           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.language( |           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.attendees[0].language.translate( | ||||||
|             "meeting_url" |             "meeting_url" | ||||||
|           )}: <a href="${meetingUrl}" alt="${this.calEvent.language( |           )}: <a href="${meetingUrl}" alt="${this.calEvent.attendees[0].language.translate( | ||||||
|             "meeting_url" |             "meeting_url" | ||||||
|           )}" style="color: #3E3E3E" target="_blank">${meetingUrl}</a></div>` |           )}" style="color: #3E3E3E" target="_blank">${meetingUrl}</a></div>` | ||||||
|         } |         } | ||||||
|  | @ -345,14 +347,14 @@ ${getRichDescription(this.calEvent)} | ||||||
|       return ` |       return ` | ||||||
|       <p style="height: 6px"></p> |       <p style="height: 6px"></p> | ||||||
|       <div style="line-height: 6px;"> |       <div style="line-height: 6px;"> | ||||||
|         <p style="color: #494949;">${this.calEvent.language("where")}</p> |         <p style="color: #494949;">${this.calEvent.attendees[0].language.translate("where")}</p> | ||||||
|         <p style="color: #494949; font-weight: 400; line-height: 24px;">${providerName} ${ |         <p style="color: #494949; font-weight: 400; line-height: 24px;">${providerName} ${ | ||||||
|         hangoutLink && |         hangoutLink && | ||||||
|         `<a href="${hangoutLink}" target="_blank" alt="${this.calEvent.language( |         `<a href="${hangoutLink}" target="_blank" alt="${this.calEvent.attendees[0].language.translate( | ||||||
|           "meeting_url" |           "meeting_url" | ||||||
|         )}"><img src="${linkIcon()}" width="12px"></img></a>` |         )}"><img src="${linkIcon()}" width="12px"></img></a>` | ||||||
|       }</p> |       }</p> | ||||||
|         <div style="color: #494949; font-weight: 400; line-height: 24px;"><a href="${hangoutLink}" alt="${this.calEvent.language( |         <div style="color: #494949; font-weight: 400; line-height: 24px;"><a href="${hangoutLink}" alt="${this.calEvent.attendees[0].language.translate( | ||||||
|         "meeting_url" |         "meeting_url" | ||||||
|       )}" style="color: #3E3E3E" target="_blank">${hangoutLink}</a></div> |       )}" style="color: #3E3E3E" target="_blank">${hangoutLink}</a></div> | ||||||
|       </div> |       </div> | ||||||
|  | @ -362,7 +364,7 @@ ${getRichDescription(this.calEvent)} | ||||||
|     return ` |     return ` | ||||||
|     <p style="height: 6px"></p> |     <p style="height: 6px"></p> | ||||||
|     <div style="line-height: 6px;"> |     <div style="line-height: 6px;"> | ||||||
|       <p style="color: #494949;">${this.calEvent.language("where")}</p> |       <p style="color: #494949;">${this.calEvent.attendees[0].language.translate("where")}</p> | ||||||
|       <p style="color: #494949; font-weight: 400; line-height: 24px;">${ |       <p style="color: #494949; font-weight: 400; line-height: 24px;">${ | ||||||
|         providerName || this.calEvent.location |         providerName || this.calEvent.location | ||||||
|       }</p> |       }</p> | ||||||
|  |  | ||||||
|  | @ -33,14 +33,14 @@ export default class OrganizerCancelledEmail extends OrganizerScheduledEmail { | ||||||
|     return { |     return { | ||||||
|       from: `Cal.com <${this.getMailerOptions().from}>`, |       from: `Cal.com <${this.getMailerOptions().from}>`, | ||||||
|       to: toAddresses.join(","), |       to: toAddresses.join(","), | ||||||
|       subject: `${this.calEvent.language("event_cancelled_subject", { |       subject: `${this.calEvent.organizer.language.translate("event_cancelled_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.attendees[0].name, |         name: this.calEvent.attendees[0].name, | ||||||
|         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("dddd").toLowerCase() |           this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("MMMM").toLowerCase() |           this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -51,8 +51,8 @@ export default class OrganizerCancelledEmail extends OrganizerScheduledEmail { | ||||||
| 
 | 
 | ||||||
|   protected getTextBody(): string { |   protected getTextBody(): string { | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("event_request_cancelled")} | ${this.calEvent.organizer.language.translate("event_request_cancelled")} | ||||||
| ${this.calEvent.language("emailed_you_and_any_other_attendees")} | ${this.calEvent.organizer.language.translate("emailed_you_and_any_other_attendees")} | ||||||
| ${this.getWhat()} | ${this.getWhat()} | ||||||
| ${this.getWhen()} | ${this.getWhen()} | ||||||
| ${this.getLocation()} | ${this.getLocation()} | ||||||
|  | @ -61,14 +61,14 @@ ${this.getAdditionalNotes()} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("event_cancelled_subject", { |     const headerContent = this.calEvent.organizer.language.translate("event_cancelled_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.attendees[0].name, |       name: this.calEvent.attendees[0].name, | ||||||
|       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("dddd").toLowerCase() |         this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("MMMM").toLowerCase() |         this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -81,8 +81,8 @@ ${this.getAdditionalNotes()} | ||||||
|       <div style="background-color:#F5F5F5;"> |       <div style="background-color:#F5F5F5;"> | ||||||
|         ${emailSchedulingBodyHeader("xCircle")} |         ${emailSchedulingBodyHeader("xCircle")} | ||||||
|         ${emailScheduledBodyHeaderContent( |         ${emailScheduledBodyHeaderContent( | ||||||
|           this.calEvent.language("event_request_cancelled"), |           this.calEvent.organizer.language.translate("event_request_cancelled"), | ||||||
|           this.calEvent.language("emailed_you_and_any_other_attendees") |           this.calEvent.organizer.language.translate("emailed_you_and_any_other_attendees") | ||||||
|         )} |         )} | ||||||
|         ${emailSchedulingBodyDivider()} |         ${emailSchedulingBodyDivider()} | ||||||
|         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> |         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> | ||||||
|  |  | ||||||
|  | @ -27,14 +27,14 @@ export default class OrganizerPaymentRefundFailedEmail extends OrganizerSchedule | ||||||
|     return { |     return { | ||||||
|       from: `Cal.com <${this.getMailerOptions().from}>`, |       from: `Cal.com <${this.getMailerOptions().from}>`, | ||||||
|       to: toAddresses.join(","), |       to: toAddresses.join(","), | ||||||
|       subject: `${this.calEvent.language("refund_failed_subject", { |       subject: `${this.calEvent.organizer.language.translate("refund_failed_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.attendees[0].name, |         name: this.calEvent.attendees[0].name, | ||||||
|         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("dddd").toLowerCase() |           this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("MMMM").toLowerCase() |           this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -45,11 +45,15 @@ export default class OrganizerPaymentRefundFailedEmail extends OrganizerSchedule | ||||||
| 
 | 
 | ||||||
|   protected getTextBody(): string { |   protected getTextBody(): string { | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("a_refund_failed")} | ${this.calEvent.organizer.language.translate("a_refund_failed")} | ||||||
| ${this.calEvent.language("check_with_provider_and_user", { user: this.calEvent.attendees[0].name })} | ${this.calEvent.organizer.language.translate("check_with_provider_and_user", { | ||||||
|  |   user: this.calEvent.attendees[0].name, | ||||||
|  | })} | ||||||
| ${ | ${ | ||||||
|   this.calEvent.paymentInfo && |   this.calEvent.paymentInfo && | ||||||
|   this.calEvent.language("error_message", { errorMessage: this.calEvent.paymentInfo.reason }) |   this.calEvent.organizer.language.translate("error_message", { | ||||||
|  |     errorMessage: this.calEvent.paymentInfo.reason, | ||||||
|  |   }) | ||||||
| } | } | ||||||
| ${this.getWhat()} | ${this.getWhat()} | ||||||
| ${this.getWhen()} | ${this.getWhen()} | ||||||
|  | @ -59,14 +63,14 @@ ${this.getAdditionalNotes()} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("refund_failed_subject", { |     const headerContent = this.calEvent.organizer.language.translate("refund_failed_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.attendees[0].name, |       name: this.calEvent.attendees[0].name, | ||||||
|       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("dddd").toLowerCase() |         this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("MMMM").toLowerCase() |         this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -91,14 +95,14 @@ ${this.getAdditionalNotes()} | ||||||
|                       <tbody> |                       <tbody> | ||||||
|                         <tr> |                         <tr> | ||||||
|                           <td align="center" style="font-size:0px;padding:10px 25px;padding-top:24px;padding-bottom:0px;word-break:break-word;"> |                           <td align="center" style="font-size:0px;padding:10px 25px;padding-top:24px;padding-bottom:0px;word-break:break-word;"> | ||||||
|                             <div style="font-family:Roboto, Helvetica, sans-serif;font-size:24px;font-weight:700;line-height:24px;text-align:center;color:#292929;">${this.calEvent.language( |                             <div style="font-family:Roboto, Helvetica, sans-serif;font-size:24px;font-weight:700;line-height:24px;text-align:center;color:#292929;">${this.calEvent.organizer.language.translate( | ||||||
|                               "a_refund_failed" |                               "a_refund_failed" | ||||||
|                             )}</div> |                             )}</div> | ||||||
|                           </td> |                           </td> | ||||||
|                         </tr> |                         </tr> | ||||||
|                         <tr> |                         <tr> | ||||||
|                           <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"> |                           <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"> | ||||||
|                             <div style="font-family:Roboto, Helvetica, sans-serif;font-size:16px;font-weight:400;line-height:24px;text-align:center;color:#494949;">${this.calEvent.language( |                             <div style="font-family:Roboto, Helvetica, sans-serif;font-size:16px;font-weight:400;line-height:24px;text-align:center;color:#494949;">${this.calEvent.organizer.language.translate( | ||||||
|                               "check_with_provider_and_user", |                               "check_with_provider_and_user", | ||||||
|                               { user: this.calEvent.attendees[0].name } |                               { user: this.calEvent.attendees[0].name } | ||||||
|                             )}</div> |                             )}</div> | ||||||
|  | @ -174,7 +178,7 @@ ${this.getAdditionalNotes()} | ||||||
|         refundInformation = ` |         refundInformation = ` | ||||||
|         <tr> |         <tr> | ||||||
|           <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"> |           <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;"> | ||||||
|             <div style="font-family:Roboto, Helvetica, sans-serif;font-size:16px;font-weight:400;line-height:24px;text-align:center;color:#494949;">${this.calEvent.language( |             <div style="font-family:Roboto, Helvetica, sans-serif;font-size:16px;font-weight:400;line-height:24px;text-align:center;color:#494949;">${this.calEvent.organizer.language.translate( | ||||||
|               "error_message", |               "error_message", | ||||||
|               { errorMessage: paymentInfo.reason } |               { errorMessage: paymentInfo.reason } | ||||||
|             )}</div> |             )}</div> | ||||||
|  |  | ||||||
|  | @ -34,14 +34,14 @@ export default class OrganizerRequestEmail extends OrganizerScheduledEmail { | ||||||
|     return { |     return { | ||||||
|       from: `Cal.com <${this.getMailerOptions().from}>`, |       from: `Cal.com <${this.getMailerOptions().from}>`, | ||||||
|       to: toAddresses.join(","), |       to: toAddresses.join(","), | ||||||
|       subject: `${this.calEvent.language("event_awaiting_approval_subject", { |       subject: `${this.calEvent.organizer.language.translate("event_awaiting_approval_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.attendees[0].name, |         name: this.calEvent.attendees[0].name, | ||||||
|         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("dddd").toLowerCase() |           this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("MMMM").toLowerCase() |           this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -52,26 +52,26 @@ export default class OrganizerRequestEmail extends OrganizerScheduledEmail { | ||||||
| 
 | 
 | ||||||
|   protected getTextBody(): string { |   protected getTextBody(): string { | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("event_awaiting_approval")} | ${this.calEvent.organizer.language.translate("event_awaiting_approval")} | ||||||
| ${this.calEvent.language("someone_requested_an_event")} | ${this.calEvent.organizer.language.translate("someone_requested_an_event")} | ||||||
| ${this.getWhat()} | ${this.getWhat()} | ||||||
| ${this.getWhen()} | ${this.getWhen()} | ||||||
| ${this.getLocation()} | ${this.getLocation()} | ||||||
| ${this.getAdditionalNotes()} | ${this.getAdditionalNotes()} | ||||||
| ${this.calEvent.language("confirm_or_reject_request")} | ${this.calEvent.organizer.language.translate("confirm_or_reject_request")} | ||||||
| ${process.env.BASE_URL} + "/bookings/upcoming" | ${process.env.BASE_URL} + "/bookings/upcoming" | ||||||
| `.replace(/(<([^>]+)>)/gi, "");
 | `.replace(/(<([^>]+)>)/gi, "");
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("event_awaiting_approval_subject", { |     const headerContent = this.calEvent.organizer.language.translate("event_awaiting_approval_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.attendees[0].name, |       name: this.calEvent.attendees[0].name, | ||||||
|       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("dddd").toLowerCase() |         this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("MMMM").toLowerCase() |         this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -85,8 +85,8 @@ ${process.env.BASE_URL} + "/bookings/upcoming" | ||||||
|       <div style="background-color:#F5F5F5;"> |       <div style="background-color:#F5F5F5;"> | ||||||
|         ${emailSchedulingBodyHeader("calendarCircle")} |         ${emailSchedulingBodyHeader("calendarCircle")} | ||||||
|         ${emailScheduledBodyHeaderContent( |         ${emailScheduledBodyHeaderContent( | ||||||
|           this.calEvent.language("event_awaiting_approval"), |           this.calEvent.organizer.language.translate("event_awaiting_approval"), | ||||||
|           this.calEvent.language("someone_requested_an_event") |           this.calEvent.organizer.language.translate("someone_requested_an_event") | ||||||
|         )} |         )} | ||||||
|         ${emailSchedulingBodyDivider()} |         ${emailSchedulingBodyDivider()} | ||||||
|         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> |         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> | ||||||
|  | @ -166,7 +166,7 @@ ${process.env.BASE_URL} + "/bookings/upcoming" | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getManageLink(): string { |   protected getManageLink(): string { | ||||||
|     const manageText = this.calEvent.language("confirm_or_reject_request"); |     const manageText = this.calEvent.organizer.language.translate("confirm_or_reject_request"); | ||||||
|     const manageLink = process.env.BASE_URL + "/bookings/upcoming"; |     const manageLink = process.env.BASE_URL + "/bookings/upcoming"; | ||||||
|     return `<a style="color: #FFFFFF; text-decoration: none;" href="${manageLink}" target="_blank">${manageText} <img src="${linkIcon()}" width="12px"></img></a>`; |     return `<a style="color: #FFFFFF; text-decoration: none;" href="${manageLink}" target="_blank">${manageText} <img src="${linkIcon()}" width="12px"></img></a>`; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -34,14 +34,14 @@ export default class OrganizerRequestReminderEmail extends OrganizerScheduledEma | ||||||
|     return { |     return { | ||||||
|       from: `Cal.com <${this.getMailerOptions().from}>`, |       from: `Cal.com <${this.getMailerOptions().from}>`, | ||||||
|       to: toAddresses.join(","), |       to: toAddresses.join(","), | ||||||
|       subject: `${this.calEvent.language("event_awaiting_approval_subject", { |       subject: `${this.calEvent.organizer.language.translate("event_awaiting_approval_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.attendees[0].name, |         name: this.calEvent.attendees[0].name, | ||||||
|         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("dddd").toLowerCase() |           this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("MMMM").toLowerCase() |           this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -52,26 +52,26 @@ export default class OrganizerRequestReminderEmail extends OrganizerScheduledEma | ||||||
| 
 | 
 | ||||||
|   protected getTextBody(): string { |   protected getTextBody(): string { | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("event_still_awaiting_approval")} | ${this.calEvent.organizer.language.translate("event_still_awaiting_approval")} | ||||||
| ${this.calEvent.language("someone_requested_an_event")} | ${this.calEvent.organizer.language.translate("someone_requested_an_event")} | ||||||
| ${this.getWhat()} | ${this.getWhat()} | ||||||
| ${this.getWhen()} | ${this.getWhen()} | ||||||
| ${this.getLocation()} | ${this.getLocation()} | ||||||
| ${this.getAdditionalNotes()} | ${this.getAdditionalNotes()} | ||||||
| ${this.calEvent.language("confirm_or_reject_request")} | ${this.calEvent.organizer.language.translate("confirm_or_reject_request")} | ||||||
| ${process.env.BASE_URL} + "/bookings/upcoming" | ${process.env.BASE_URL} + "/bookings/upcoming" | ||||||
| `.replace(/(<([^>]+)>)/gi, "");
 | `.replace(/(<([^>]+)>)/gi, "");
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("event_awaiting_approval_subject", { |     const headerContent = this.calEvent.organizer.language.translate("event_awaiting_approval_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.attendees[0].name, |       name: this.calEvent.attendees[0].name, | ||||||
|       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("dddd").toLowerCase() |         this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("MMMM").toLowerCase() |         this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -84,8 +84,8 @@ ${process.env.BASE_URL} + "/bookings/upcoming" | ||||||
|       <div style="background-color:#F5F5F5;"> |       <div style="background-color:#F5F5F5;"> | ||||||
|         ${emailSchedulingBodyHeader("calendarCircle")} |         ${emailSchedulingBodyHeader("calendarCircle")} | ||||||
|         ${emailScheduledBodyHeaderContent( |         ${emailScheduledBodyHeaderContent( | ||||||
|           this.calEvent.language("event_still_awaiting_approval"), |           this.calEvent.organizer.language.translate("event_still_awaiting_approval"), | ||||||
|           this.calEvent.language("someone_requested_an_event") |           this.calEvent.organizer.language.translate("someone_requested_an_event") | ||||||
|         )} |         )} | ||||||
|         ${emailSchedulingBodyDivider()} |         ${emailSchedulingBodyDivider()} | ||||||
|         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> |         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> | ||||||
|  | @ -165,7 +165,7 @@ ${process.env.BASE_URL} + "/bookings/upcoming" | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getManageLink(): string { |   protected getManageLink(): string { | ||||||
|     const manageText = this.calEvent.language("confirm_or_reject_request"); |     const manageText = this.calEvent.organizer.language.translate("confirm_or_reject_request"); | ||||||
|     const manageLink = process.env.BASE_URL + "/bookings/upcoming"; |     const manageLink = process.env.BASE_URL + "/bookings/upcoming"; | ||||||
|     return `<a style="color: #FFFFFF; text-decoration: none;" href="${manageLink}" target="_blank">${manageText} <img src="${linkIcon()}" width="12px"></img></a>`; |     return `<a style="color: #FFFFFF; text-decoration: none;" href="${manageLink}" target="_blank">${manageText} <img src="${linkIcon()}" width="12px"></img></a>`; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -39,14 +39,14 @@ export default class OrganizerRescheduledEmail extends OrganizerScheduledEmail { | ||||||
|       }, |       }, | ||||||
|       from: `Cal.com <${this.getMailerOptions().from}>`, |       from: `Cal.com <${this.getMailerOptions().from}>`, | ||||||
|       to: toAddresses.join(","), |       to: toAddresses.join(","), | ||||||
|       subject: `${this.calEvent.language("rescheduled_event_type_subject", { |       subject: `${this.calEvent.organizer.language.translate("rescheduled_event_type_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.attendees[0].name, |         name: this.calEvent.attendees[0].name, | ||||||
|         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("dddd").toLowerCase() |           this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("MMMM").toLowerCase() |           this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -57,26 +57,26 @@ export default class OrganizerRescheduledEmail extends OrganizerScheduledEmail { | ||||||
| 
 | 
 | ||||||
|   protected getTextBody(): string { |   protected getTextBody(): string { | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("event_has_been_rescheduled")} | ${this.calEvent.organizer.language.translate("event_has_been_rescheduled")} | ||||||
| ${this.calEvent.language("emailed_you_and_any_other_attendees")} | ${this.calEvent.organizer.language.translate("emailed_you_and_any_other_attendees")} | ||||||
| ${this.getWhat()} | ${this.getWhat()} | ||||||
| ${this.getWhen()} | ${this.getWhen()} | ||||||
| ${this.getLocation()} | ${this.getLocation()} | ||||||
| ${this.getAdditionalNotes()} | ${this.getAdditionalNotes()} | ||||||
| ${this.calEvent.language("need_to_reschedule_or_cancel")} | ${this.calEvent.organizer.language.translate("need_to_reschedule_or_cancel")} | ||||||
| ${getCancelLink(this.calEvent)} | ${getCancelLink(this.calEvent)} | ||||||
| `.replace(/(<([^>]+)>)/gi, "");
 | `.replace(/(<([^>]+)>)/gi, "");
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("rescheduled_event_type_subject", { |     const headerContent = this.calEvent.organizer.language.translate("rescheduled_event_type_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.attendees[0].name, |       name: this.calEvent.attendees[0].name, | ||||||
|       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("dddd").toLowerCase() |         this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("MMMM").toLowerCase() |         this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -89,8 +89,8 @@ ${getCancelLink(this.calEvent)} | ||||||
|       <div style="background-color:#F5F5F5;"> |       <div style="background-color:#F5F5F5;"> | ||||||
|         ${emailSchedulingBodyHeader("calendarCircle")} |         ${emailSchedulingBodyHeader("calendarCircle")} | ||||||
|         ${emailScheduledBodyHeaderContent( |         ${emailScheduledBodyHeaderContent( | ||||||
|           this.calEvent.language("event_has_been_rescheduled"), |           this.calEvent.organizer.language.translate("event_has_been_rescheduled"), | ||||||
|           this.calEvent.language("emailed_you_and_any_other_attendees") |           this.calEvent.organizer.language.translate("emailed_you_and_any_other_attendees") | ||||||
|         )} |         )} | ||||||
|         ${emailSchedulingBodyDivider()} |         ${emailSchedulingBodyDivider()} | ||||||
|         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> |         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> | ||||||
|  |  | ||||||
|  | @ -59,7 +59,7 @@ export default class OrganizerScheduledEmail { | ||||||
|         .map((v, i) => (i === 1 ? v + 1 : v)) as DateArray, |         .map((v, i) => (i === 1 ? v + 1 : v)) as DateArray, | ||||||
|       startInputType: "utc", |       startInputType: "utc", | ||||||
|       productId: "calendso/ics", |       productId: "calendso/ics", | ||||||
|       title: this.calEvent.language("ics_event_title", { |       title: this.calEvent.organizer.language.translate("ics_event_title", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.attendees[0].name, |         name: this.calEvent.attendees[0].name, | ||||||
|       }), |       }), | ||||||
|  | @ -96,14 +96,14 @@ export default class OrganizerScheduledEmail { | ||||||
|       }, |       }, | ||||||
|       from: `Cal.com <${this.getMailerOptions().from}>`, |       from: `Cal.com <${this.getMailerOptions().from}>`, | ||||||
|       to: toAddresses.join(","), |       to: toAddresses.join(","), | ||||||
|       subject: `${this.calEvent.language("confirmed_event_type_subject", { |       subject: `${this.calEvent.organizer.language.translate("confirmed_event_type_subject", { | ||||||
|         eventType: this.calEvent.type, |         eventType: this.calEvent.type, | ||||||
|         name: this.calEvent.attendees[0].name, |         name: this.calEvent.attendees[0].name, | ||||||
|         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |         date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|           "h:mma" |           "h:mma" | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("dddd").toLowerCase() |           this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|         )}, ${this.calEvent.language( |         )}, ${this.calEvent.organizer.language.translate( | ||||||
|           this.getOrganizerStart().format("MMMM").toLowerCase() |           this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |         )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|       })}`,
 |       })}`,
 | ||||||
|  | @ -121,8 +121,8 @@ export default class OrganizerScheduledEmail { | ||||||
| 
 | 
 | ||||||
|   protected getTextBody(): string { |   protected getTextBody(): string { | ||||||
|     return ` |     return ` | ||||||
| ${this.calEvent.language("new_event_scheduled")} | ${this.calEvent.organizer.language.translate("new_event_scheduled")} | ||||||
| ${this.calEvent.language("emailed_you_and_any_other_attendees")} | ${this.calEvent.organizer.language.translate("emailed_you_and_any_other_attendees")} | ||||||
| 
 | 
 | ||||||
| ${getRichDescription(this.calEvent)} | ${getRichDescription(this.calEvent)} | ||||||
| `.trim();
 | `.trim();
 | ||||||
|  | @ -133,14 +133,14 @@ ${getRichDescription(this.calEvent)} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getHtmlBody(): string { |   protected getHtmlBody(): string { | ||||||
|     const headerContent = this.calEvent.language("confirmed_event_type_subject", { |     const headerContent = this.calEvent.organizer.language.translate("confirmed_event_type_subject", { | ||||||
|       eventType: this.calEvent.type, |       eventType: this.calEvent.type, | ||||||
|       name: this.calEvent.attendees[0].name, |       name: this.calEvent.attendees[0].name, | ||||||
|       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( |       date: `${this.getOrganizerStart().format("h:mma")} - ${this.getOrganizerEnd().format( | ||||||
|         "h:mma" |         "h:mma" | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("dddd").toLowerCase() |         this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("MMMM").toLowerCase() |         this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 |       )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format("YYYY")}`,
 | ||||||
|     }); |     }); | ||||||
|  | @ -153,8 +153,8 @@ ${getRichDescription(this.calEvent)} | ||||||
|       <div style="background-color:#F5F5F5;"> |       <div style="background-color:#F5F5F5;"> | ||||||
|         ${emailSchedulingBodyHeader("checkCircle")} |         ${emailSchedulingBodyHeader("checkCircle")} | ||||||
|         ${emailScheduledBodyHeaderContent( |         ${emailScheduledBodyHeaderContent( | ||||||
|           this.calEvent.language("new_event_scheduled"), |           this.calEvent.organizer.language.translate("new_event_scheduled"), | ||||||
|           this.calEvent.language("emailed_you_and_any_other_attendees") |           this.calEvent.organizer.language.translate("emailed_you_and_any_other_attendees") | ||||||
|         )} |         )} | ||||||
|         ${emailSchedulingBodyDivider()} |         ${emailSchedulingBodyDivider()} | ||||||
|         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> |         <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--> | ||||||
|  | @ -223,8 +223,8 @@ ${getRichDescription(this.calEvent)} | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected getManageLink(): string { |   protected getManageLink(): string { | ||||||
|     const manageText = this.calEvent.language("manage_this_event"); |     const manageText = this.calEvent.organizer.language.translate("manage_this_event"); | ||||||
|     return `<p>${this.calEvent.language( |     return `<p>${this.calEvent.organizer.language.translate( | ||||||
|       "need_to_reschedule_or_cancel" |       "need_to_reschedule_or_cancel" | ||||||
|     )}</p><p style="font-weight: 400; line-height: 24px;"><a href="${getCancelLink( |     )}</p><p style="font-weight: 400; line-height: 24px;"><a href="${getCancelLink( | ||||||
|       this.calEvent |       this.calEvent | ||||||
|  | @ -234,7 +234,7 @@ ${getRichDescription(this.calEvent)} | ||||||
|   protected getWhat(): string { |   protected getWhat(): string { | ||||||
|     return ` |     return ` | ||||||
|     <div style="line-height: 6px;"> |     <div style="line-height: 6px;"> | ||||||
|       <p style="color: #494949;">${this.calEvent.language("what")}</p> |       <p style="color: #494949;">${this.calEvent.organizer.language.translate("what")}</p> | ||||||
|       <p style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.type}</p> |       <p style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.type}</p> | ||||||
|     </div>`;
 |     </div>`;
 | ||||||
|   } |   } | ||||||
|  | @ -243,11 +243,11 @@ ${getRichDescription(this.calEvent)} | ||||||
|     return ` |     return ` | ||||||
|     <p style="height: 6px"></p> |     <p style="height: 6px"></p> | ||||||
|     <div style="line-height: 6px;"> |     <div style="line-height: 6px;"> | ||||||
|       <p style="color: #494949;">${this.calEvent.language("when")}</p> |       <p style="color: #494949;">${this.calEvent.organizer.language.translate("when")}</p> | ||||||
|       <p style="color: #494949; font-weight: 400; line-height: 24px;"> |       <p style="color: #494949; font-weight: 400; line-height: 24px;"> | ||||||
|       ${this.calEvent.language( |       ${this.calEvent.organizer.language.translate( | ||||||
|         this.getOrganizerStart().format("dddd").toLowerCase() |         this.getOrganizerStart().format("dddd").toLowerCase() | ||||||
|       )}, ${this.calEvent.language( |       )}, ${this.calEvent.organizer.language.translate( | ||||||
|       this.getOrganizerStart().format("MMMM").toLowerCase() |       this.getOrganizerStart().format("MMMM").toLowerCase() | ||||||
|     )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format( |     )} ${this.getOrganizerStart().format("D")}, ${this.getOrganizerStart().format( | ||||||
|       "YYYY" |       "YYYY" | ||||||
|  | @ -262,7 +262,7 @@ ${getRichDescription(this.calEvent)} | ||||||
|     const attendees = this.calEvent.attendees |     const attendees = this.calEvent.attendees | ||||||
|       .map((attendee) => { |       .map((attendee) => { | ||||||
|         return `<div style="color: #494949; font-weight: 400; line-height: 24px;">${ |         return `<div style="color: #494949; font-weight: 400; line-height: 24px;">${ | ||||||
|           attendee?.name || `${this.calEvent.language("guest")}` |           attendee?.name || `${this.calEvent.organizer.language.translate("guest")}` | ||||||
|         } <span style="color: #888888"><a href="mailto:${attendee.email}" style="color: #888888;">${ |         } <span style="color: #888888"><a href="mailto:${attendee.email}" style="color: #888888;">${ | ||||||
|           attendee.email |           attendee.email | ||||||
|         }</a></span></div>`;
 |         }</a></span></div>`;
 | ||||||
|  | @ -271,14 +271,16 @@ ${getRichDescription(this.calEvent)} | ||||||
| 
 | 
 | ||||||
|     const organizer = `<div style="color: #494949; font-weight: 400; line-height: 24px;">${ |     const organizer = `<div style="color: #494949; font-weight: 400; line-height: 24px;">${ | ||||||
|       this.calEvent.organizer.name |       this.calEvent.organizer.name | ||||||
|     } - ${this.calEvent.language("organizer")} <span style="color: #888888"><a href="mailto:${ |     } - ${this.calEvent.organizer.language.translate( | ||||||
|  |       "organizer" | ||||||
|  |     )} <span style="color: #888888"><a href="mailto:${ | ||||||
|       this.calEvent.organizer.email |       this.calEvent.organizer.email | ||||||
|     }" style="color: #888888;">${this.calEvent.organizer.email}</a></span></div>`;
 |     }" style="color: #888888;">${this.calEvent.organizer.email}</a></span></div>`;
 | ||||||
| 
 | 
 | ||||||
|     return ` |     return ` | ||||||
|     <p style="height: 6px"></p> |     <p style="height: 6px"></p> | ||||||
|     <div style="line-height: 6px;"> |     <div style="line-height: 6px;"> | ||||||
|       <p style="color: #494949;">${this.calEvent.language("who")}</p> |       <p style="color: #494949;">${this.calEvent.organizer.language.translate("who")}</p> | ||||||
|       ${organizer + attendees} |       ${organizer + attendees} | ||||||
|     </div>`;
 |     </div>`;
 | ||||||
|   } |   } | ||||||
|  | @ -287,7 +289,7 @@ ${getRichDescription(this.calEvent)} | ||||||
|     return ` |     return ` | ||||||
|     <p style="height: 6px"></p> |     <p style="height: 6px"></p> | ||||||
|     <div style="line-height: 6px;"> |     <div style="line-height: 6px;"> | ||||||
|       <p style="color: #494949;">${this.calEvent.language("additional_notes")}</p> |       <p style="color: #494949;">${this.calEvent.organizer.language.translate("additional_notes")}</p> | ||||||
|       <p style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.description}</p> |       <p style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.description}</p> | ||||||
|     </div> |     </div> | ||||||
|     `;
 |     `;
 | ||||||
|  | @ -309,30 +311,30 @@ ${getRichDescription(this.calEvent)} | ||||||
|       return ` |       return ` | ||||||
|       <p style="height: 6px"></p> |       <p style="height: 6px"></p> | ||||||
|       <div style="line-height: 6px;"> |       <div style="line-height: 6px;"> | ||||||
|         <p style="color: #494949;">${this.calEvent.language("where")}</p> |         <p style="color: #494949;">${this.calEvent.organizer.language.translate("where")}</p> | ||||||
|         <p style="color: #494949; font-weight: 400; line-height: 24px;">${providerName} ${ |         <p style="color: #494949; font-weight: 400; line-height: 24px;">${providerName} ${ | ||||||
|         meetingUrl && |         meetingUrl && | ||||||
|         `<a href="${meetingUrl}" target="_blank" alt="${this.calEvent.language( |         `<a href="${meetingUrl}" target="_blank" alt="${this.calEvent.organizer.language.translate( | ||||||
|           "meeting_url" |           "meeting_url" | ||||||
|         )}"><img src="${linkIcon()}" width="12px"></img></a>` |         )}"><img src="${linkIcon()}" width="12px"></img></a>` | ||||||
|       }</p> |       }</p> | ||||||
|         ${ |         ${ | ||||||
|           meetingId && |           meetingId && | ||||||
|           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.language( |           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.organizer.language.translate( | ||||||
|             "meeting_id" |             "meeting_id" | ||||||
|           )}: <span>${meetingId}</span></div>` |           )}: <span>${meetingId}</span></div>` | ||||||
|         } |         } | ||||||
|         ${ |         ${ | ||||||
|           meetingPassword && |           meetingPassword && | ||||||
|           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.language( |           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.organizer.language.translate( | ||||||
|             "meeting_password" |             "meeting_password" | ||||||
|           )}: <span>${meetingPassword}</span></div>` |           )}: <span>${meetingPassword}</span></div>` | ||||||
|         } |         } | ||||||
|         ${ |         ${ | ||||||
|           meetingUrl && |           meetingUrl && | ||||||
|           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.language( |           `<div style="color: #494949; font-weight: 400; line-height: 24px;">${this.calEvent.organizer.language.translate( | ||||||
|             "meeting_url" |             "meeting_url" | ||||||
|           )}: <a href="${meetingUrl}" alt="${this.calEvent.language( |           )}: <a href="${meetingUrl}" alt="${this.calEvent.organizer.language.translate( | ||||||
|             "meeting_url" |             "meeting_url" | ||||||
|           )}" style="color: #3E3E3E" target="_blank">${meetingUrl}</a></div>` |           )}" style="color: #3E3E3E" target="_blank">${meetingUrl}</a></div>` | ||||||
|         } |         } | ||||||
|  | @ -346,14 +348,14 @@ ${getRichDescription(this.calEvent)} | ||||||
|       return ` |       return ` | ||||||
|       <p style="height: 6px"></p> |       <p style="height: 6px"></p> | ||||||
|       <div style="line-height: 6px;"> |       <div style="line-height: 6px;"> | ||||||
|         <p style="color: #494949;">${this.calEvent.language("where")}</p> |         <p style="color: #494949;">${this.calEvent.organizer.language.translate("where")}</p> | ||||||
|         <p style="color: #494949; font-weight: 400; line-height: 24px;">${providerName} ${ |         <p style="color: #494949; font-weight: 400; line-height: 24px;">${providerName} ${ | ||||||
|         hangoutLink && |         hangoutLink && | ||||||
|         `<a href="${hangoutLink}" target="_blank" alt="${this.calEvent.language( |         `<a href="${hangoutLink}" target="_blank" alt="${this.calEvent.organizer.language.translate( | ||||||
|           "meeting_url" |           "meeting_url" | ||||||
|         )}"><img src="${linkIcon()}" width="12px"></img></a>` |         )}"><img src="${linkIcon()}" width="12px"></img></a>` | ||||||
|       }</p> |       }</p> | ||||||
|         <div style="color: #494949; font-weight: 400; line-height: 24px;"><a href="${hangoutLink}" alt="${this.calEvent.language( |         <div style="color: #494949; font-weight: 400; line-height: 24px;"><a href="${hangoutLink}" alt="${this.calEvent.organizer.language.translate( | ||||||
|         "meeting_url" |         "meeting_url" | ||||||
|       )}" style="color: #3E3E3E" target="_blank">${hangoutLink}</a></div> |       )}" style="color: #3E3E3E" target="_blank">${hangoutLink}</a></div> | ||||||
|       </div> |       </div> | ||||||
|  | @ -363,7 +365,7 @@ ${getRichDescription(this.calEvent)} | ||||||
|     return ` |     return ` | ||||||
|     <p style="height: 6px"></p> |     <p style="height: 6px"></p> | ||||||
|     <div style="line-height: 6px;"> |     <div style="line-height: 6px;"> | ||||||
|       <p style="color: #494949;">${this.calEvent.language("where")}</p> |       <p style="color: #494949;">${this.calEvent.organizer.language.translate("where")}</p> | ||||||
|       <p style="color: #494949; font-weight: 400; line-height: 24px;">${ |       <p style="color: #494949; font-weight: 400; line-height: 24px;">${ | ||||||
|         providerName || this.calEvent.location |         providerName || this.calEvent.location | ||||||
|       }</p> |       }</p> | ||||||
|  |  | ||||||
|  | @ -8,7 +8,6 @@ import { createEvent, updateEvent } from "@lib/integrations/calendar/CalendarMan | ||||||
| import { AdditionInformation, CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar"; | import { AdditionInformation, CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar"; | ||||||
| import { LocationType } from "@lib/location"; | import { LocationType } from "@lib/location"; | ||||||
| import prisma from "@lib/prisma"; | import prisma from "@lib/prisma"; | ||||||
| import { Ensure } from "@lib/types/utils"; |  | ||||||
| import { createMeeting, updateMeeting, VideoCallData } from "@lib/videoClient"; | import { createMeeting, updateMeeting, VideoCallData } from "@lib/videoClient"; | ||||||
| 
 | 
 | ||||||
| export type Event = AdditionInformation & VideoCallData; | export type Event = AdditionInformation & VideoCallData; | ||||||
|  | @ -118,7 +117,7 @@ export default class EventManager { | ||||||
|    * |    * | ||||||
|    * @param event |    * @param event | ||||||
|    */ |    */ | ||||||
|   public async create(event: Ensure<CalendarEvent, "language">): Promise<CreateUpdateResult> { |   public async create(event: CalendarEvent): Promise<CreateUpdateResult> { | ||||||
|     const evt = processLocation(event); |     const evt = processLocation(event); | ||||||
|     const isDedicated = evt.location ? isDedicatedIntegration(evt.location) : null; |     const isDedicated = evt.location ? isDedicatedIntegration(evt.location) : null; | ||||||
| 
 | 
 | ||||||
|  | @ -158,10 +157,7 @@ export default class EventManager { | ||||||
|    * |    * | ||||||
|    * @param event |    * @param event | ||||||
|    */ |    */ | ||||||
|   public async update( |   public async update(event: CalendarEvent, rescheduleUid: string): Promise<CreateUpdateResult> { | ||||||
|     event: Ensure<CalendarEvent, "language">, |  | ||||||
|     rescheduleUid: string |  | ||||||
|   ): Promise<CreateUpdateResult> { |  | ||||||
|     const evt = processLocation(event); |     const evt = processLocation(event); | ||||||
| 
 | 
 | ||||||
|     if (!rescheduleUid) { |     if (!rescheduleUid) { | ||||||
|  | @ -293,7 +289,7 @@ export default class EventManager { | ||||||
|    * @param event |    * @param event | ||||||
|    * @private |    * @private | ||||||
|    */ |    */ | ||||||
|   private createVideoEvent(event: Ensure<CalendarEvent, "language">): Promise<EventResult> { |   private createVideoEvent(event: CalendarEvent): Promise<EventResult> { | ||||||
|     const credential = this.getVideoCredential(event); |     const credential = this.getVideoCredential(event); | ||||||
| 
 | 
 | ||||||
|     if (credential) { |     if (credential) { | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ export type Person = { | ||||||
|   name: string; |   name: string; | ||||||
|   email: string; |   email: string; | ||||||
|   timeZone: string; |   timeZone: string; | ||||||
|  |   language: { translate: TFunction; locale: string }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export interface EntryPoint { | export interface EntryPoint { | ||||||
|  | @ -46,7 +47,6 @@ export interface CalendarEvent { | ||||||
|   organizer: Person; |   organizer: Person; | ||||||
|   attendees: Person[]; |   attendees: Person[]; | ||||||
|   conferenceData?: ConferenceData; |   conferenceData?: ConferenceData; | ||||||
|   language: TFunction; |  | ||||||
|   additionInformation?: AdditionInformation; |   additionInformation?: AdditionInformation; | ||||||
|   uid?: string | null; |   uid?: string | null; | ||||||
|   videoCallData?: VideoCallData; |   videoCallData?: VideoCallData; | ||||||
|  |  | ||||||
|  | @ -10,7 +10,6 @@ import logger from "@lib/logger"; | ||||||
| import DailyVideoApiAdapter from "./integrations/Daily/DailyVideoApiAdapter"; | import DailyVideoApiAdapter from "./integrations/Daily/DailyVideoApiAdapter"; | ||||||
| import ZoomVideoApiAdapter from "./integrations/Zoom/ZoomVideoApiAdapter"; | import ZoomVideoApiAdapter from "./integrations/Zoom/ZoomVideoApiAdapter"; | ||||||
| import { CalendarEvent } from "./integrations/calendar/interfaces/Calendar"; | import { CalendarEvent } from "./integrations/calendar/interfaces/Calendar"; | ||||||
| import { Ensure } from "./types/utils"; |  | ||||||
| 
 | 
 | ||||||
| const log = logger.getChildLogger({ prefix: ["[lib] videoClient"] }); | const log = logger.getChildLogger({ prefix: ["[lib] videoClient"] }); | ||||||
| 
 | 
 | ||||||
|  | @ -56,10 +55,7 @@ const getBusyVideoTimes = (withCredentials: Credential[]) => | ||||||
|     results.reduce((acc, availability) => acc.concat(availability), []) |     results.reduce((acc, availability) => acc.concat(availability), []) | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
| const createMeeting = async ( | const createMeeting = async (credential: Credential, calEvent: CalendarEvent): Promise<EventResult> => { | ||||||
|   credential: Credential, |  | ||||||
|   calEvent: Ensure<CalendarEvent, "language"> |  | ||||||
| ): Promise<EventResult> => { |  | ||||||
|   const uid: string = getUid(calEvent); |   const uid: string = getUid(calEvent); | ||||||
| 
 | 
 | ||||||
|   if (!credential) { |   if (!credential) { | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ import { CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar"; | ||||||
| 
 | 
 | ||||||
| type ContentType = "application/json" | "application/x-www-form-urlencoded"; | type ContentType = "application/json" | "application/x-www-form-urlencoded"; | ||||||
| 
 | 
 | ||||||
| function applyTemplate(template: string, data: Omit<CalendarEvent, "language">, contentType: ContentType) { | function applyTemplate(template: string, data: CalendarEvent, contentType: ContentType) { | ||||||
|   const compiled = compile(template)(data); |   const compiled = compile(template)(data); | ||||||
|   if (contentType === "application/json") { |   if (contentType === "application/json") { | ||||||
|     return jsonParse(compiled); |     return jsonParse(compiled); | ||||||
|  | @ -25,7 +25,9 @@ const sendPayload = async ( | ||||||
|   triggerEvent: string, |   triggerEvent: string, | ||||||
|   createdAt: string, |   createdAt: string, | ||||||
|   subscriberUrl: string, |   subscriberUrl: string, | ||||||
|   data: Omit<CalendarEvent, "language"> & { metadata?: { [key: string]: string } }, |   data: CalendarEvent & { | ||||||
|  |     metadata?: { [key: string]: string }; | ||||||
|  |   }, | ||||||
|   template?: string | null |   template?: string | null | ||||||
| ) => { | ) => { | ||||||
|   if (!subscriberUrl || !data) { |   if (!subscriberUrl || !data) { | ||||||
|  |  | ||||||
|  | @ -43,8 +43,6 @@ const authorized = async ( | ||||||
| const log = logger.getChildLogger({ prefix: ["[api] book:user"] }); | const log = logger.getChildLogger({ prefix: ["[api] book:user"] }); | ||||||
| 
 | 
 | ||||||
| export default async function handler(req: NextApiRequest, res: NextApiResponse): Promise<void> { | export default async function handler(req: NextApiRequest, res: NextApiResponse): Promise<void> { | ||||||
|   const t = await getTranslation(req.body.language ?? "en", "common"); |  | ||||||
| 
 |  | ||||||
|   const session = await getSession({ req: req }); |   const session = await getSession({ req: req }); | ||||||
|   if (!session?.user?.id) { |   if (!session?.user?.id) { | ||||||
|     return res.status(401).json({ message: "Not authenticated" }); |     return res.status(401).json({ message: "Not authenticated" }); | ||||||
|  | @ -71,6 +69,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|       name: true, |       name: true, | ||||||
|       username: true, |       username: true, | ||||||
|       destinationCalendar: true, |       destinationCalendar: true, | ||||||
|  |       locale: true, | ||||||
|     }, |     }, | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|  | @ -78,6 +77,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|     return res.status(404).json({ message: "User not found" }); |     return res.status(404).json({ message: "User not found" }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   const tOrganizer = await getTranslation(currentUser.locale ?? "en", "common"); | ||||||
|  | 
 | ||||||
|   if (req.method === "PATCH") { |   if (req.method === "PATCH") { | ||||||
|     const booking = await prisma.booking.findFirst({ |     const booking = await prisma.booking.findFirst({ | ||||||
|       where: { |       where: { | ||||||
|  | @ -112,6 +113,20 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|       return res.status(400).json({ message: "booking already confirmed" }); |       return res.status(400).json({ message: "booking already confirmed" }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     const attendeesListPromises = booking.attendees.map(async (attendee) => { | ||||||
|  |       return { | ||||||
|  |         name: attendee.name, | ||||||
|  |         email: attendee.email, | ||||||
|  |         timeZone: attendee.timeZone, | ||||||
|  |         language: { | ||||||
|  |           translate: await getTranslation(attendee.locale ?? "en", "common"), | ||||||
|  |           locale: attendee.locale ?? "en", | ||||||
|  |         }, | ||||||
|  |       }; | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const attendeesList = await Promise.all(attendeesListPromises); | ||||||
|  | 
 | ||||||
|     const evt: CalendarEvent = { |     const evt: CalendarEvent = { | ||||||
|       type: booking.title, |       type: booking.title, | ||||||
|       title: booking.title, |       title: booking.title, | ||||||
|  | @ -122,11 +137,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|         email: currentUser.email, |         email: currentUser.email, | ||||||
|         name: currentUser.name || "Unnamed", |         name: currentUser.name || "Unnamed", | ||||||
|         timeZone: currentUser.timeZone, |         timeZone: currentUser.timeZone, | ||||||
|  |         language: { translate: tOrganizer, locale: currentUser.locale ?? "en" }, | ||||||
|       }, |       }, | ||||||
|       attendees: booking.attendees, |       attendees: attendeesList, | ||||||
|       location: booking.location ?? "", |       location: booking.location ?? "", | ||||||
|       uid: booking.uid, |       uid: booking.uid, | ||||||
|       language: t, |  | ||||||
|       destinationCalendar: booking?.destinationCalendar || currentUser.destinationCalendar, |       destinationCalendar: booking?.destinationCalendar || currentUser.destinationCalendar, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -136,6 +136,7 @@ const userSelect = Prisma.validator<Prisma.UserArgs>()({ | ||||||
|     credentials: true, |     credentials: true, | ||||||
|     bufferTime: true, |     bufferTime: true, | ||||||
|     destinationCalendar: true, |     destinationCalendar: true, | ||||||
|  |     locale: true, | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | @ -152,6 +153,7 @@ const getUserNameWithBookingCounts = async (eventTypeId: number, selectedUserNam | ||||||
|     select: { |     select: { | ||||||
|       id: true, |       id: true, | ||||||
|       username: true, |       username: true, | ||||||
|  |       locale: true, | ||||||
|     }, |     }, | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|  | @ -180,8 +182,8 @@ type User = Prisma.UserGetPayload<typeof userSelect>; | ||||||
| export default async function handler(req: NextApiRequest, res: NextApiResponse) { | export default async function handler(req: NextApiRequest, res: NextApiResponse) { | ||||||
|   const reqBody = req.body as BookingCreateBody; |   const reqBody = req.body as BookingCreateBody; | ||||||
|   const eventTypeId = reqBody.eventTypeId; |   const eventTypeId = reqBody.eventTypeId; | ||||||
|   const t = await getTranslation(reqBody.language ?? "en", "common"); |   const tAttendees = await getTranslation(reqBody.language ?? "en", "common"); | ||||||
| 
 |   const tGuests = await getTranslation("en", "common"); | ||||||
|   log.debug(`Booking eventType ${eventTypeId} started`); |   log.debug(`Booking eventType ${eventTypeId} started`); | ||||||
| 
 | 
 | ||||||
|   const isTimeInPast = (time: string): boolean => { |   const isTimeInPast = (time: string): boolean => { | ||||||
|  | @ -244,6 +246,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|     users.push(eventTypeUser); |     users.push(eventTypeUser); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   const organizer = await prisma.user.findUnique({ | ||||||
|  |     where: { | ||||||
|  |       id: users[0].id, | ||||||
|  |     }, | ||||||
|  |     select: { | ||||||
|  |       locale: true, | ||||||
|  |     }, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   const tOrganizer = await getTranslation(organizer?.locale ?? "en", "common"); | ||||||
|  | 
 | ||||||
|   if (eventType.schedulingType === SchedulingType.ROUND_ROBIN) { |   if (eventType.schedulingType === SchedulingType.ROUND_ROBIN) { | ||||||
|     const bookingCounts = await getUserNameWithBookingCounts( |     const bookingCounts = await getUserNameWithBookingCounts( | ||||||
|       eventTypeId, |       eventTypeId, | ||||||
|  | @ -253,25 +266,41 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|     users = getLuckyUsers(users, bookingCounts); |     users = getLuckyUsers(users, bookingCounts); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const invitee = [{ email: reqBody.email, name: reqBody.name, timeZone: reqBody.timeZone }]; |   const invitee = [ | ||||||
|  |     { | ||||||
|  |       email: reqBody.email, | ||||||
|  |       name: reqBody.name, | ||||||
|  |       timeZone: reqBody.timeZone, | ||||||
|  |       language: { translate: tAttendees, locale: reqBody.language ?? "en" }, | ||||||
|  |     }, | ||||||
|  |   ]; | ||||||
|   const guests = (reqBody.guests || []).map((guest) => { |   const guests = (reqBody.guests || []).map((guest) => { | ||||||
|     const g = { |     const g = { | ||||||
|       email: guest, |       email: guest, | ||||||
|       name: "", |       name: "", | ||||||
|       timeZone: reqBody.timeZone, |       timeZone: reqBody.timeZone, | ||||||
|  |       language: { translate: tGuests, locale: "en" }, | ||||||
|     }; |     }; | ||||||
|     return g; |     return g; | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   const teamMembers = |   const teamMemberPromises = | ||||||
|     eventType.schedulingType === SchedulingType.COLLECTIVE |     eventType.schedulingType === SchedulingType.COLLECTIVE | ||||||
|       ? users.slice(1).map((user) => ({ |       ? users.slice(1).map(async function (user) { | ||||||
|           email: user.email || "", |           return { | ||||||
|           name: user.name || "", |             email: user.email || "", | ||||||
|           timeZone: user.timeZone, |             name: user.name || "", | ||||||
|         })) |             timeZone: user.timeZone, | ||||||
|  |             language: { | ||||||
|  |               translate: await getTranslation(user.locale ?? "en", "common"), | ||||||
|  |               locale: user.locale ?? "en", | ||||||
|  |             }, | ||||||
|  |           }; | ||||||
|  |         }) | ||||||
|       : []; |       : []; | ||||||
| 
 | 
 | ||||||
|  |   const teamMembers = await Promise.all(teamMemberPromises); | ||||||
|  | 
 | ||||||
|   const attendeesList = [...invitee, ...guests, ...teamMembers]; |   const attendeesList = [...invitee, ...guests, ...teamMembers]; | ||||||
| 
 | 
 | ||||||
|   const seed = `${users[0].username}:${dayjs(req.body.start).utc().format()}:${new Date().getTime()}`; |   const seed = `${users[0].username}:${dayjs(req.body.start).utc().format()}:${new Date().getTime()}`; | ||||||
|  | @ -282,7 +311,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|     eventType: eventType.title, |     eventType: eventType.title, | ||||||
|     eventName: eventType.eventName, |     eventName: eventType.eventName, | ||||||
|     host: users[0].name || "Nameless", |     host: users[0].name || "Nameless", | ||||||
|     t, |     t: tOrganizer, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const description = |   const description = | ||||||
|  | @ -294,7 +323,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
| 
 | 
 | ||||||
|   const evt: CalendarEvent = { |   const evt: CalendarEvent = { | ||||||
|     type: eventType.title, |     type: eventType.title, | ||||||
|     title: getEventName(eventNameObject), |     title: getEventName(eventNameObject), //this needs to be either forced in english, or fetched for each attendee and organizer separately
 | ||||||
|     description, |     description, | ||||||
|     startTime: reqBody.start, |     startTime: reqBody.start, | ||||||
|     endTime: reqBody.end, |     endTime: reqBody.end, | ||||||
|  | @ -302,10 +331,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|       name: users[0].name || "Nameless", |       name: users[0].name || "Nameless", | ||||||
|       email: users[0].email || "Email-less", |       email: users[0].email || "Email-less", | ||||||
|       timeZone: users[0].timeZone, |       timeZone: users[0].timeZone, | ||||||
|  |       language: { translate: tOrganizer, locale: organizer?.locale ?? "en" }, | ||||||
|     }, |     }, | ||||||
|     attendees: attendeesList, |     attendees: attendeesList, | ||||||
|     location: reqBody.location, // Will be processed by the EventManager later.
 |     location: reqBody.location, // Will be processed by the EventManager later.
 | ||||||
|     language: t, |  | ||||||
|     /** For team events, we will need to handle each member destinationCalendar eventually */ |     /** For team events, we will need to handle each member destinationCalendar eventually */ | ||||||
|     destinationCalendar: eventType.destinationCalendar || users[0].destinationCalendar, |     destinationCalendar: eventType.destinationCalendar || users[0].destinationCalendar, | ||||||
|   }; |   }; | ||||||
|  | @ -343,7 +372,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|         }, |         }, | ||||||
|         attendees: { |         attendees: { | ||||||
|           createMany: { |           createMany: { | ||||||
|             data: evt.attendees, |             data: evt.attendees.map((attendee) => { | ||||||
|  |               //if attendee is team member, it should fetch their locale not booker's locale
 | ||||||
|  |               //perhaps make email fetch request to see if his locale is stored, else
 | ||||||
|  |               const retObj = { | ||||||
|  |                 name: attendee.name, | ||||||
|  |                 email: attendee.email, | ||||||
|  |                 timeZone: attendee.timeZone, | ||||||
|  |                 locale: attendee.language.locale, | ||||||
|  |               }; | ||||||
|  |               return retObj; | ||||||
|  |             }), | ||||||
|           }, |           }, | ||||||
|         }, |         }, | ||||||
|         user: { |         user: { | ||||||
|  |  | ||||||
|  | @ -89,11 +89,25 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|       name: true, |       name: true, | ||||||
|       email: true, |       email: true, | ||||||
|       timeZone: true, |       timeZone: true, | ||||||
|  |       locale: true, | ||||||
|     }, |     }, | ||||||
|     rejectOnNotFound: true, |     rejectOnNotFound: true, | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   const t = await getTranslation(req.body.language ?? "en", "common"); |   const attendeesListPromises = bookingToDelete.attendees.map(async (attendee) => { | ||||||
|  |     return { | ||||||
|  |       name: attendee.name, | ||||||
|  |       email: attendee.email, | ||||||
|  |       timeZone: attendee.timeZone, | ||||||
|  |       language: { | ||||||
|  |         translate: await getTranslation(attendee.locale ?? "en", "common"), | ||||||
|  |         locale: attendee.locale ?? "en", | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   const attendeesList = await Promise.all(attendeesListPromises); | ||||||
|  |   const tOrganizer = await getTranslation(organizer.locale ?? "en", "common"); | ||||||
| 
 | 
 | ||||||
|   const evt: CalendarEvent = { |   const evt: CalendarEvent = { | ||||||
|     title: bookingToDelete?.title, |     title: bookingToDelete?.title, | ||||||
|  | @ -105,14 +119,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|       email: organizer.email, |       email: organizer.email, | ||||||
|       name: organizer.name ?? "Nameless", |       name: organizer.name ?? "Nameless", | ||||||
|       timeZone: organizer.timeZone, |       timeZone: organizer.timeZone, | ||||||
|  |       language: { translate: tOrganizer, locale: organizer.locale ?? "en" }, | ||||||
|     }, |     }, | ||||||
|     attendees: bookingToDelete?.attendees.map((attendee) => { |     attendees: attendeesList, | ||||||
|       const retObj = { name: attendee.name, email: attendee.email, timeZone: attendee.timeZone }; |  | ||||||
|       return retObj; |  | ||||||
|     }), |  | ||||||
|     uid: bookingToDelete?.uid, |     uid: bookingToDelete?.uid, | ||||||
|     location: bookingToDelete?.location, |     location: bookingToDelete?.location, | ||||||
|     language: t, |  | ||||||
|     destinationCalendar: bookingToDelete?.destinationCalendar || bookingToDelete?.user.destinationCalendar, |     destinationCalendar: bookingToDelete?.destinationCalendar || bookingToDelete?.user.destinationCalendar, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  | @ -168,11 +179,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|         email: bookingToDelete.user?.email ?? "dev@calendso.com", |         email: bookingToDelete.user?.email ?? "dev@calendso.com", | ||||||
|         name: bookingToDelete.user?.name ?? "no user", |         name: bookingToDelete.user?.name ?? "no user", | ||||||
|         timeZone: bookingToDelete.user?.timeZone ?? "", |         timeZone: bookingToDelete.user?.timeZone ?? "", | ||||||
|  |         language: { translate: tOrganizer, locale: organizer.locale ?? "en" }, | ||||||
|       }, |       }, | ||||||
|       attendees: bookingToDelete.attendees, |       attendees: attendeesList, | ||||||
|       location: bookingToDelete.location ?? "", |       location: bookingToDelete.location ?? "", | ||||||
|       uid: bookingToDelete.uid ?? "", |       uid: bookingToDelete.uid ?? "", | ||||||
|       language: t, |  | ||||||
|       destinationCalendar: bookingToDelete?.destinationCalendar || bookingToDelete?.user.destinationCalendar, |       destinationCalendar: bookingToDelete?.destinationCalendar || bookingToDelete?.user.destinationCalendar, | ||||||
|     }; |     }; | ||||||
|     await refund(bookingToDelete, evt); |     await refund(bookingToDelete, evt); | ||||||
|  |  | ||||||
|  | @ -73,7 +73,21 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|         continue; |         continue; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       const t = await getTranslation(user.locale ?? "en", "common"); |       const tOrganizer = await getTranslation(user.locale ?? "en", "common"); | ||||||
|  | 
 | ||||||
|  |       const attendeesListPromises = booking.attendees.map(async (attendee) => { | ||||||
|  |         return { | ||||||
|  |           name: attendee.name, | ||||||
|  |           email: attendee.email, | ||||||
|  |           timeZone: attendee.timeZone, | ||||||
|  |           language: { | ||||||
|  |             translate: await getTranslation(attendee.locale ?? "en", "common"), | ||||||
|  |             locale: attendee.locale ?? "en", | ||||||
|  |           }, | ||||||
|  |         }; | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       const attendeesList = await Promise.all(attendeesListPromises); | ||||||
| 
 | 
 | ||||||
|       const evt: CalendarEvent = { |       const evt: CalendarEvent = { | ||||||
|         type: booking.title, |         type: booking.title, | ||||||
|  | @ -86,10 +100,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|           email: user.email, |           email: user.email, | ||||||
|           name, |           name, | ||||||
|           timeZone: user.timeZone, |           timeZone: user.timeZone, | ||||||
|  |           language: { translate: tOrganizer, locale: user.locale ?? "en" }, | ||||||
|         }, |         }, | ||||||
|         attendees: booking.attendees, |         attendees: attendeesList, | ||||||
|         uid: booking.uid, |         uid: booking.uid, | ||||||
|         language: t, |  | ||||||
|         destinationCalendar: booking.destinationCalendar || user.destinationCalendar, |         destinationCalendar: booking.destinationCalendar || user.destinationCalendar, | ||||||
|       }; |       }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -63,8 +63,10 @@ test.describe("integrations", () => { | ||||||
|     body.payload.location = dynamic; |     body.payload.location = dynamic; | ||||||
|     for (const attendee of body.payload.attendees) { |     for (const attendee of body.payload.attendees) { | ||||||
|       attendee.timeZone = dynamic; |       attendee.timeZone = dynamic; | ||||||
|  |       attendee.language = dynamic; | ||||||
|     } |     } | ||||||
|     body.payload.organizer.timeZone = dynamic; |     body.payload.organizer.timeZone = dynamic; | ||||||
|  |     body.payload.organizer.language = dynamic; | ||||||
|     body.payload.uid = dynamic; |     body.payload.uid = dynamic; | ||||||
|     body.payload.additionInformation = dynamic; |     body.payload.additionInformation = dynamic; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1 +1 @@ | ||||||
| {"triggerEvent":"BOOKING_CREATED","createdAt":"[redacted/dynamic]","payload":{"type":"30min","title":"30min between Pro Example and Test Testson","description":"","startTime":"[redacted/dynamic]","endTime":"[redacted/dynamic]","organizer":{"name":"Pro Example","email":"pro@example.com","timeZone":"[redacted/dynamic]"},"attendees":[{"email":"test@example.com","name":"Test Testson","timeZone":"[redacted/dynamic]"}],"location":"[redacted/dynamic]","destinationCalendar":null,"uid":"[redacted/dynamic]","metadata":{},"additionInformation":"[redacted/dynamic]"}} | {"triggerEvent":"BOOKING_CREATED","createdAt":"[redacted/dynamic]","payload":{"type":"30min","title":"30min between Pro Example and Test Testson","description":"","startTime":"[redacted/dynamic]","endTime":"[redacted/dynamic]","organizer":{"name":"Pro Example","email":"pro@example.com","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"},"attendees":[{"email":"test@example.com","name":"Test Testson","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"}],"location":"[redacted/dynamic]","destinationCalendar":null,"uid":"[redacted/dynamic]","metadata":{},"additionInformation":"[redacted/dynamic]"}} | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | -- AlterTable | ||||||
|  | ALTER TABLE "Attendee" ADD COLUMN     "locale" TEXT DEFAULT E'en'; | ||||||
|  | @ -199,6 +199,7 @@ model Attendee { | ||||||
|   email     String |   email     String | ||||||
|   name      String |   name      String | ||||||
|   timeZone  String |   timeZone  String | ||||||
|  |   locale    String?  @default("en") | ||||||
|   booking   Booking? @relation(fields: [bookingId], references: [id]) |   booking   Booking? @relation(fields: [bookingId], references: [id]) | ||||||
|   bookingId Int? |   bookingId Int? | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ export const _AttendeeModel = z.object({ | ||||||
|   email: z.string(), |   email: z.string(), | ||||||
|   name: z.string(), |   name: z.string(), | ||||||
|   timeZone: z.string(), |   timeZone: z.string(), | ||||||
|  |   locale: z.string().nullish(), | ||||||
|   bookingId: z.number().int().nullish(), |   bookingId: z.number().int().nullish(), | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Syed Ali Shahbaz
						Syed Ali Shahbaz