Skip to content

Commit d9b3f86

Browse files
feat: add setting to disable phone only sms notification (#21038)
* feat: add setting to disable phone only sms notification * Update apps/web/public/static/locales/en/common.json Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> --------- Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
1 parent 99dc583 commit d9b3f86

9 files changed

Lines changed: 88 additions & 10 deletions

File tree

apps/web/public/static/locales/en/common.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2570,6 +2570,8 @@
25702570
"org_admin_no_slots|cta": "Open users availability",
25712571
"organization_no_slots_notification_switch_title": "Get notifications when your team has no availability",
25722572
"organization_no_slots_notification_switch_description": "Admins will get email notifications when a user tries to book a team member and is faced with 'No availability'. We trigger this email after two occurrences and remind you every 7 days per user. ",
2573+
"organization_disable_phone_only_sms_notifications_switch_title": "Disable SMS notifications for phone only event types",
2574+
"organization_disable_phone_only_sms_notifications_switch_description": "Disable automated SMS notifications for event types that only have phone number(attendeePhoneNumber) as required question with email as optional or not required",
25732575
"email_team_invite|subject|added_to_org": "{{user}} added you to the organization {{team}} on {{appName}}",
25742576
"email_team_invite|subject|invited_to_org": "{{user}} invited you to join the organization {{team}} on {{appName}}",
25752577
"email_team_invite|subject|added_to_subteam": "{{user}} added you to the team {{team}} of organization {{parentTeamName}} on {{appName}}",
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"use client"
2+
import { useState } from "react";
3+
4+
import { useLocale } from "@calcom/lib/hooks/useLocale";
5+
import type { RouterOutputs } from "@calcom/trpc";
6+
import { trpc } from "@calcom/trpc";
7+
import { SettingsToggle } from "@calcom/ui/components/form";
8+
import { showToast } from "@calcom/ui/components/toast";
9+
10+
interface GeneralViewProps {
11+
currentOrg: RouterOutputs["viewer"]["organizations"]["listCurrent"];
12+
isAdminOrOwner: boolean;
13+
}
14+
15+
export const DisablePhoneOnlySMSNotificationsSwitch = ({ currentOrg, isAdminOrOwner }: GeneralViewProps) => {
16+
const { t } = useLocale();
17+
const utils = trpc.useUtils();
18+
const [disablePhoneOnlySMSNotificationsActive, setDisablePhoneOnlySMSNotificationsActive] = useState(
19+
!!currentOrg.organizationSettings.disablePhoneOnlySMSNotifications
20+
);
21+
22+
const mutation = trpc.viewer.organizations.update.useMutation({
23+
onSuccess: async () => {
24+
showToast(t("settings_updated_successfully"), "success");
25+
},
26+
onError: () => {
27+
showToast(t("error_updating_settings"), "error");
28+
},
29+
onSettled: () => {
30+
utils.viewer.organizations.listCurrent.invalidate();
31+
},
32+
});
33+
34+
if (!isAdminOrOwner) return null;
35+
36+
return (
37+
<>
38+
<SettingsToggle
39+
toggleSwitchAtTheEnd={true}
40+
title={t("organization_disable_phone_only_sms_notifications_switch_title")}
41+
disabled={mutation?.isPending}
42+
description={t("organization_disable_phone_only_sms_notifications_switch_description")}
43+
checked={disablePhoneOnlySMSNotificationsActive}
44+
onCheckedChange={(checked) => {
45+
mutation.mutate({
46+
disablePhoneOnlySMSNotifications: checked,
47+
});
48+
setDisablePhoneOnlySMSNotificationsActive(checked);
49+
}}
50+
switchContainerClassName="mt-6"
51+
/>
52+
</>
53+
);
54+
};

packages/features/ee/organizations/pages/settings/general.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { Select } from "@calcom/ui/components/form";
2121
import { SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui/components/skeleton";
2222
import { showToast } from "@calcom/ui/components/toast";
2323

24+
import { DisablePhoneOnlySMSNotificationsSwitch } from "../components/DisablePhoneOnlySMSNotificationsSwitch";
2425
import { LockEventTypeSwitch } from "../components/LockEventTypeSwitch";
2526
import { NoSlotsNotificationSwitch } from "../components/NoSlotsNotificationSwitch";
2627

@@ -82,6 +83,7 @@ const OrgGeneralView = () => {
8283

8384
<LockEventTypeSwitch currentOrg={currentOrg} isAdminOrOwner={!!isAdminOrOwner} />
8485
<NoSlotsNotificationSwitch currentOrg={currentOrg} isAdminOrOwner={!!isAdminOrOwner} />
86+
<DisablePhoneOnlySMSNotificationsSwitch currentOrg={currentOrg} isAdminOrOwner={!!isAdminOrOwner} />
8587
</LicenseRequired>
8688
);
8789
};

packages/lib/server/repository/organization.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ export class OrganizationRepository {
268268
allowSEOIndexing: true,
269269
orgProfileRedirectsToVerifiedDomain: true,
270270
orgAutoAcceptEmail: true,
271+
disablePhoneOnlySMSNotifications: true,
271272
},
272273
});
273274

@@ -285,6 +286,7 @@ export class OrganizationRepository {
285286
allowSEOIndexing: organizationSettings?.allowSEOIndexing,
286287
orgProfileRedirectsToVerifiedDomain: organizationSettings?.orgProfileRedirectsToVerifiedDomain,
287288
orgAutoAcceptEmail: organizationSettings?.orgAutoAcceptEmail,
289+
disablePhoneOnlySMSNotifications: organizationSettings?.disablePhoneOnlySMSNotifications,
288290
},
289291
user: {
290292
role: membership?.role,
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "OrganizationSettings" ADD COLUMN "disablePhoneOnlySMSNotifications" BOOLEAN NOT NULL DEFAULT false;

packages/prisma/schema.prisma

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ model EventType {
175175
rescheduleWithSameRoundRobinHost Boolean @default(false)
176176
177177
secondaryEmailId Int?
178-
secondaryEmail SecondaryEmail? @relation(fields: [secondaryEmailId], references: [id], onDelete: Cascade)
178+
secondaryEmail SecondaryEmail? @relation(fields: [secondaryEmailId], references: [id], onDelete: Cascade)
179179
180180
@@unique([userId, slug])
181181
@@unique([teamId, slug])
@@ -206,12 +206,12 @@ model Credential {
206206
paymentStatus String?
207207
billingCycleStart Int?
208208
209-
destinationCalendars DestinationCalendar[]
210-
selectedCalendars SelectedCalendar[]
211-
invalid Boolean? @default(false)
212-
CalendarCache CalendarCache[]
213-
references BookingReference[]
214-
delegationCredentialId String?
209+
destinationCalendars DestinationCalendar[]
210+
selectedCalendars SelectedCalendar[]
211+
invalid Boolean? @default(false)
212+
CalendarCache CalendarCache[]
213+
references BookingReference[]
214+
delegationCredentialId String?
215215
delegationCredential DelegationCredential? @relation(fields: [delegationCredentialId], references: [id], onDelete: Cascade)
216216
217217
@@index([userId])
@@ -531,6 +531,7 @@ model OrganizationSettings {
531531
isAdminAPIEnabled Boolean @default(false)
532532
allowSEOIndexing Boolean @default(false)
533533
orgProfileRedirectsToVerifiedDomain Boolean @default(false)
534+
disablePhoneOnlySMSNotifications Boolean @default(false)
534535
}
535536

536537
enum MembershipRole {
@@ -1467,17 +1468,18 @@ view BookingTimeStatus {
14671468
model CalendarCache {
14681469
// To be made required in a followup
14691470
id String? @default(uuid())
1470-
1471+
14711472
// The key would be the unique URL that is requested by the user
14721473
key String
14731474
value Json
14741475
expiresAt DateTime
14751476
credentialId Int
14761477
userId Int?
14771478
credential Credential? @relation(fields: [credentialId], references: [id], onDelete: Cascade)
1479+
14781480
@@id([credentialId, key])
1479-
@@index([userId, key])
14801481
@@unique([credentialId, key])
1482+
@@index([userId, key])
14811483
}
14821484

14831485
enum RedirectType {

packages/sms/sms-manager.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,21 @@ const handleSendingSMS = ({
2929
parent: {
3030
select: {
3131
isOrganization: true,
32+
organizationSettings: {
33+
select: {
34+
disablePhoneOnlySMSNotifications: true,
35+
},
36+
},
3237
},
3338
},
3439
},
3540
});
3641

37-
if (!team?.parent?.isOrganization) return;
42+
if (
43+
!team?.parent?.isOrganization ||
44+
team?.parent?.organizationSettings?.disablePhoneOnlySMSNotifications
45+
)
46+
return;
3847

3948
await checkSMSRateLimit({ identifier: `handleSendingSMS:team:${teamId}`, rateLimitingType: "sms" });
4049
const sms = twilio.sendSMS(reminderPhone, smsMessage, senderID, teamId);

packages/trpc/server/routers/viewer/organizations/update.handler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ const updateOrganizationSettings = async ({
4949
data.orgProfileRedirectsToVerifiedDomain = input.orgProfileRedirectsToVerifiedDomain;
5050
}
5151

52+
if (input.hasOwnProperty("disablePhoneOnlySMSNotifications")) {
53+
data.disablePhoneOnlySMSNotifications = input.disablePhoneOnlySMSNotifications;
54+
}
55+
5256
// If no settings values have changed lets skip this update
5357
if (Object.keys(data).length === 0) return;
5458

packages/trpc/server/routers/viewer/organizations/update.schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export const ZUpdateInputSchema = z.object({
3434
adminGetsNoSlotsNotification: z.boolean().optional(),
3535
allowSEOIndexing: z.boolean().optional(),
3636
orgProfileRedirectsToVerifiedDomain: z.boolean().optional(),
37+
disablePhoneOnlySMSNotifications: z.boolean().optional(),
3738
});
3839

3940
export type TUpdateInputSchema = z.infer<typeof ZUpdateInputSchema>;

0 commit comments

Comments
 (0)