feat: add option to disable sending transcription emails (#19065)
* feat: add option to disable sending transcription emails * fix: types and tests * fix: type error * fix: type err * fix: type err --------- Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Keith Williams <keithwillcode@gmail.com>
This commit is contained in:
co-authored by
Peer Richelsen
Keith Williams
parent
6ca76707da
commit
808de26401
@@ -88,6 +88,7 @@ const getEventTypes = async (userId: number, teamIds?: number[]) => {
|
||||
position: true,
|
||||
recurringEvent: true,
|
||||
requiresConfirmation: true,
|
||||
canSendCalVideoTranscriptionEmails: true,
|
||||
team: { select: { slug: true } },
|
||||
schedulingType: true,
|
||||
teamId: true,
|
||||
|
||||
@@ -30,6 +30,7 @@ export const getEventTypesFromDB = async (id: number) => {
|
||||
eventName: true,
|
||||
recurringEvent: true,
|
||||
requiresConfirmation: true,
|
||||
canSendCalVideoTranscriptionEmails: true,
|
||||
userId: true,
|
||||
successRedirectUrl: true,
|
||||
customInputs: true,
|
||||
|
||||
@@ -21,6 +21,7 @@ export const getBooking = async (bookingId: number) => {
|
||||
select: {
|
||||
teamId: true,
|
||||
parentId: true,
|
||||
canSendCalVideoTranscriptionEmails: true,
|
||||
},
|
||||
},
|
||||
user: {
|
||||
|
||||
@@ -158,6 +158,12 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const bookingReference = await getBookingReference(room);
|
||||
const booking = await getBooking(bookingReference.bookingId as number);
|
||||
|
||||
if (!booking.eventType?.canSendCalVideoTranscriptionEmails) {
|
||||
return res.status(200).json({
|
||||
message: `Transcription emails are disabled for this event type ${booking.eventTypeId}`,
|
||||
});
|
||||
}
|
||||
|
||||
const transcripts = await getAllTranscriptsAccessLinkFromMeetingId(meeting_id);
|
||||
|
||||
if (!transcripts || !transcripts.length)
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
"verify_email_email_header": "Verify your email address",
|
||||
"verify_email_email_button": "Verify email",
|
||||
"cal_ai_assistant": "Cal AI Assistant",
|
||||
"send_cal_video_transcription_emails": "Send Cal Video Transcription Emails",
|
||||
"description_send_cal_video_transcription_emails": "Send emails with the transcription of the Cal Video after the meeting ends. (Requires a paid plan)",
|
||||
"verify_email_change_description": "You have recently requested to change the email address you use to log into your {{appName}} account. Please click the button below to confirm your new email address.",
|
||||
"verify_email_change_success_toast": "Updated your email to {{email}}",
|
||||
"verify_email_change_failure_toast": "Failed to update email.",
|
||||
|
||||
@@ -64,6 +64,7 @@ type UserPageProps = {
|
||||
| "hidden"
|
||||
| "lockTimeZoneToggleOnBookingPage"
|
||||
| "requiresConfirmation"
|
||||
| "canSendCalVideoTranscriptionEmails"
|
||||
| "requiresBookerEmailVerification"
|
||||
| "price"
|
||||
| "currency"
|
||||
|
||||
@@ -74,6 +74,7 @@ export type EventAdvancedTabCustomClassNames = {
|
||||
};
|
||||
requiresConfirmation?: RequiresConfirmationCustomClassNames;
|
||||
bookerEmailVerification?: SettingsToggleClassNames;
|
||||
canSendCalVideoTranscriptionEmails?: SettingsToggleClassNames;
|
||||
calendarNotes?: SettingsToggleClassNames;
|
||||
eventDetailsVisibility?: SettingsToggleClassNames;
|
||||
bookingRedirect?: SettingsToggleClassNames & {
|
||||
@@ -471,6 +472,7 @@ export const EventAdvancedTab = ({
|
||||
const successRedirectUrlLocked = shouldLockDisableProps("successRedirectUrl");
|
||||
const seatsLocked = shouldLockDisableProps("seatsPerTimeSlotEnabled");
|
||||
const requiresBookerEmailVerificationProps = shouldLockDisableProps("requiresBookerEmailVerification");
|
||||
const sendCalVideoTranscriptionEmailsProps = shouldLockDisableProps("canSendCalVideoTranscriptionEmails");
|
||||
const hideCalendarNotesLocked = shouldLockDisableProps("hideCalendarNotes");
|
||||
const hideCalendarEventDetailsLocked = shouldLockDisableProps("hideCalendarEventDetails");
|
||||
const eventTypeColorLocked = shouldLockDisableProps("eventTypeColor");
|
||||
@@ -574,6 +576,29 @@ export const EventAdvancedTab = ({
|
||||
onRequiresConfirmation={setRequiresConfirmation}
|
||||
customClassNames={customClassNames?.requiresConfirmation}
|
||||
/>
|
||||
<Controller
|
||||
name="canSendCalVideoTranscriptionEmails"
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<SettingsToggle
|
||||
labelClassName={classNames(
|
||||
"text-sm",
|
||||
customClassNames?.canSendCalVideoTranscriptionEmails?.label
|
||||
)}
|
||||
toggleSwitchAtTheEnd={true}
|
||||
switchContainerClassName={classNames(
|
||||
"border-subtle rounded-lg border py-6 px-4 sm:px-6",
|
||||
customClassNames?.canSendCalVideoTranscriptionEmails?.container
|
||||
)}
|
||||
title={t("send_cal_video_transcription_emails")}
|
||||
data-testid="send-cal-video-transcription-emails"
|
||||
{...sendCalVideoTranscriptionEmailsProps}
|
||||
description={t("description_send_cal_video_transcription_emails")}
|
||||
descriptionClassName={customClassNames?.canSendCalVideoTranscriptionEmails?.description}
|
||||
checked={value}
|
||||
onCheckedChange={(e) => onChange(e)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="requiresBookerEmailVerification"
|
||||
render={({ field: { value, onChange } }) => (
|
||||
|
||||
@@ -36,14 +36,15 @@ const getEventTypesWithHiddenFromDB = async (userId: number) => {
|
||||
SELECT data."id", data."title", data."description", data."length", data."schedulingType"::text,
|
||||
data."recurringEvent", data."slug", data."hidden", data."price", data."currency",
|
||||
data."lockTimeZoneToggleOnBookingPage", data."requiresConfirmation", data."requiresBookerEmailVerification",
|
||||
data."metadata"
|
||||
data."metadata", data."canSendCalVideoTranscriptionEmails"
|
||||
FROM (
|
||||
SELECT "EventType"."id", "EventType"."title", "EventType"."description",
|
||||
"EventType"."position", "EventType"."length", "EventType"."schedulingType"::text,
|
||||
"EventType"."recurringEvent", "EventType"."slug", "EventType"."hidden",
|
||||
"EventType"."price", "EventType"."currency",
|
||||
"EventType"."lockTimeZoneToggleOnBookingPage", "EventType"."requiresConfirmation",
|
||||
"EventType"."requiresBookerEmailVerification", "EventType"."metadata"
|
||||
"EventType"."requiresBookerEmailVerification", "EventType"."metadata",
|
||||
"EventType"."canSendCalVideoTranscriptionEmails"
|
||||
FROM "EventType"
|
||||
WHERE "EventType"."teamId" IS NULL AND "EventType"."userId" = ${userId}
|
||||
UNION
|
||||
@@ -52,7 +53,8 @@ const getEventTypesWithHiddenFromDB = async (userId: number) => {
|
||||
"EventType"."recurringEvent", "EventType"."slug", "EventType"."hidden",
|
||||
"EventType"."price", "EventType"."currency",
|
||||
"EventType"."lockTimeZoneToggleOnBookingPage", "EventType"."requiresConfirmation",
|
||||
"EventType"."requiresBookerEmailVerification", "EventType"."metadata"
|
||||
"EventType"."requiresBookerEmailVerification", "EventType"."metadata",
|
||||
"EventType"."canSendCalVideoTranscriptionEmails"
|
||||
FROM "EventType"
|
||||
WHERE "EventType"."teamId" IS NULL
|
||||
AND "EventType"."id" IN (
|
||||
|
||||
@@ -12,6 +12,7 @@ export const eventTypeSelect = Prisma.validator<Prisma.EventTypeSelect>()({
|
||||
length: true,
|
||||
title: true,
|
||||
requiresConfirmation: true,
|
||||
canSendCalVideoTranscriptionEmails: true,
|
||||
requiresConfirmationForFreeEmail: true,
|
||||
requiresConfirmationWillBlockSlot: true,
|
||||
autoTranslateDescriptionEnabled: true,
|
||||
|
||||
@@ -515,6 +515,7 @@ export class EventTypeRepository {
|
||||
lockTimeZoneToggleOnBookingPage: true,
|
||||
requiresConfirmation: true,
|
||||
requiresConfirmationForFreeEmail: true,
|
||||
canSendCalVideoTranscriptionEmails: true,
|
||||
requiresConfirmationWillBlockSlot: true,
|
||||
requiresBookerEmailVerification: true,
|
||||
autoTranslateDescriptionEnabled: true,
|
||||
|
||||
@@ -100,6 +100,7 @@ export const buildEventType = (eventType?: Partial<EventType>): EventType => {
|
||||
userId: null,
|
||||
teamId: null,
|
||||
requiresBookerEmailVerification: false,
|
||||
canSendCalVideoTranscriptionEmails: true,
|
||||
useEventTypeDestinationCalendarEmail: false,
|
||||
eventName: faker.lorem.words(),
|
||||
timeZone: null,
|
||||
|
||||
@@ -86,6 +86,7 @@ export const useEventTypeForm = ({
|
||||
periodCountCalendarDays: eventType.periodCountCalendarDays ? true : false,
|
||||
schedulingType: eventType.schedulingType,
|
||||
requiresConfirmation: eventType.requiresConfirmation,
|
||||
canSendCalVideoTranscriptionEmails: eventType.canSendCalVideoTranscriptionEmails,
|
||||
requiresConfirmationWillBlockSlot: eventType.requiresConfirmationWillBlockSlot,
|
||||
requiresConfirmationForFreeEmail: eventType.requiresConfirmationForFreeEmail,
|
||||
slotInterval: eventType.slotInterval,
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "EventType" ADD COLUMN "canSendCalVideoTranscriptionEmails" BOOLEAN NOT NULL DEFAULT true;
|
||||
@@ -90,34 +90,36 @@ model EventType {
|
||||
profileId Int?
|
||||
profile Profile? @relation(fields: [profileId], references: [id], onDelete: Cascade)
|
||||
|
||||
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
||||
teamId Int?
|
||||
hashedLink HashedLink[]
|
||||
bookings Booking[]
|
||||
availability Availability[]
|
||||
webhooks Webhook[]
|
||||
destinationCalendar DestinationCalendar?
|
||||
useEventLevelSelectedCalendars Boolean @default(false)
|
||||
eventName String?
|
||||
customInputs EventTypeCustomInput[]
|
||||
parentId Int?
|
||||
parent EventType? @relation("managed_eventtype", fields: [parentId], references: [id], onDelete: Cascade)
|
||||
children EventType[] @relation("managed_eventtype")
|
||||
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
||||
teamId Int?
|
||||
hashedLink HashedLink[]
|
||||
bookings Booking[]
|
||||
availability Availability[]
|
||||
webhooks Webhook[]
|
||||
destinationCalendar DestinationCalendar?
|
||||
useEventLevelSelectedCalendars Boolean @default(false)
|
||||
eventName String?
|
||||
customInputs EventTypeCustomInput[]
|
||||
parentId Int?
|
||||
parent EventType? @relation("managed_eventtype", fields: [parentId], references: [id], onDelete: Cascade)
|
||||
children EventType[] @relation("managed_eventtype")
|
||||
/// @zod.custom(imports.eventTypeBookingFields)
|
||||
bookingFields Json?
|
||||
timeZone String?
|
||||
periodType PeriodType @default(UNLIMITED)
|
||||
bookingFields Json?
|
||||
timeZone String?
|
||||
periodType PeriodType @default(UNLIMITED)
|
||||
/// @zod.custom(imports.coerceToDate)
|
||||
periodStartDate DateTime?
|
||||
periodStartDate DateTime?
|
||||
/// @zod.custom(imports.coerceToDate)
|
||||
periodEndDate DateTime?
|
||||
periodDays Int?
|
||||
periodCountCalendarDays Boolean?
|
||||
lockTimeZoneToggleOnBookingPage Boolean @default(false)
|
||||
requiresConfirmation Boolean @default(false)
|
||||
requiresConfirmationWillBlockSlot Boolean @default(false)
|
||||
requiresConfirmationForFreeEmail Boolean @default(false)
|
||||
requiresBookerEmailVerification Boolean @default(false)
|
||||
periodEndDate DateTime?
|
||||
periodDays Int?
|
||||
periodCountCalendarDays Boolean?
|
||||
lockTimeZoneToggleOnBookingPage Boolean @default(false)
|
||||
requiresConfirmation Boolean @default(false)
|
||||
requiresConfirmationWillBlockSlot Boolean @default(false)
|
||||
requiresConfirmationForFreeEmail Boolean @default(false)
|
||||
requiresBookerEmailVerification Boolean @default(false)
|
||||
canSendCalVideoTranscriptionEmails Boolean @default(true)
|
||||
|
||||
autoTranslateDescriptionEnabled Boolean @default(false)
|
||||
/// @zod.custom(imports.recurringEventType)
|
||||
recurringEvent Json?
|
||||
|
||||
@@ -14,6 +14,7 @@ export const baseEventTypeSelect = Prisma.validator<Prisma.EventTypeSelect>()({
|
||||
lockTimeZoneToggleOnBookingPage: true,
|
||||
requiresConfirmation: true,
|
||||
requiresBookerEmailVerification: true,
|
||||
canSendCalVideoTranscriptionEmails: true,
|
||||
});
|
||||
|
||||
export const bookEventTypeSelect = Prisma.validator<Prisma.EventTypeSelect>()({
|
||||
@@ -31,6 +32,7 @@ export const bookEventTypeSelect = Prisma.validator<Prisma.EventTypeSelect>()({
|
||||
recurringEvent: true,
|
||||
lockTimeZoneToggleOnBookingPage: true,
|
||||
requiresConfirmation: true,
|
||||
canSendCalVideoTranscriptionEmails: true,
|
||||
requiresBookerEmailVerification: true,
|
||||
metadata: true,
|
||||
periodCountCalendarDays: true,
|
||||
|
||||
@@ -714,6 +714,7 @@ export const allManagedEventTypeProps: { [k in keyof Omit<Prisma.EventTypeSelect
|
||||
customInputs: true,
|
||||
disableGuests: true,
|
||||
requiresConfirmation: true,
|
||||
canSendCalVideoTranscriptionEmails: true,
|
||||
requiresConfirmationForFreeEmail: true,
|
||||
requiresConfirmationWillBlockSlot: true,
|
||||
eventName: true,
|
||||
|
||||
+5
-2
@@ -30,7 +30,10 @@ type res = Awaited<
|
||||
ReturnType<typeof MembershipRepository.findAllByUpIdIncludeMinimalEventTypes>
|
||||
>[number]["team"]["eventTypes"][number];
|
||||
|
||||
type EventType = Omit<res, "forwardParamsSuccessRedirect"> & { children?: { id: number }[] };
|
||||
type EventType = Omit<res, "forwardParamsSuccessRedirect"> & {
|
||||
children?: { id: number }[];
|
||||
canSendCalVideoTranscriptionEmails?: boolean;
|
||||
};
|
||||
|
||||
export const getTeamAndEventTypeOptions = async ({ ctx, input }: GetTeamAndEventTypeOptions) => {
|
||||
await checkRateLimitAndThrowError({
|
||||
@@ -119,7 +122,7 @@ export const getTeamAndEventTypeOptions = async ({ ctx, input }: GetTeamAndEvent
|
||||
name: profile.name,
|
||||
eventTypesLockedByOrg: parentOrgHasLockedEventTypes,
|
||||
},
|
||||
eventTypes: profileEventTypes,
|
||||
eventTypes: profileEventTypes as EventType[],
|
||||
});
|
||||
|
||||
eventTypeGroups = ([] as EventTypeGroup[]).concat(
|
||||
|
||||
Reference in New Issue
Block a user