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>
This commit is contained in:
co-authored by
Syed Ali Shahbaz
parent
99dc5837f5
commit
d9b3f8657f
@@ -2570,6 +2570,8 @@
|
||||
"org_admin_no_slots|cta": "Open users availability",
|
||||
"organization_no_slots_notification_switch_title": "Get notifications when your team has no availability",
|
||||
"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. ",
|
||||
"organization_disable_phone_only_sms_notifications_switch_title": "Disable SMS notifications for phone only event types",
|
||||
"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",
|
||||
"email_team_invite|subject|added_to_org": "{{user}} added you to the organization {{team}} on {{appName}}",
|
||||
"email_team_invite|subject|invited_to_org": "{{user}} invited you to join the organization {{team}} on {{appName}}",
|
||||
"email_team_invite|subject|added_to_subteam": "{{user}} added you to the team {{team}} of organization {{parentTeamName}} on {{appName}}",
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
"use client"
|
||||
import { useState } from "react";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { RouterOutputs } from "@calcom/trpc";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
import { SettingsToggle } from "@calcom/ui/components/form";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
interface GeneralViewProps {
|
||||
currentOrg: RouterOutputs["viewer"]["organizations"]["listCurrent"];
|
||||
isAdminOrOwner: boolean;
|
||||
}
|
||||
|
||||
export const DisablePhoneOnlySMSNotificationsSwitch = ({ currentOrg, isAdminOrOwner }: GeneralViewProps) => {
|
||||
const { t } = useLocale();
|
||||
const utils = trpc.useUtils();
|
||||
const [disablePhoneOnlySMSNotificationsActive, setDisablePhoneOnlySMSNotificationsActive] = useState(
|
||||
!!currentOrg.organizationSettings.disablePhoneOnlySMSNotifications
|
||||
);
|
||||
|
||||
const mutation = trpc.viewer.organizations.update.useMutation({
|
||||
onSuccess: async () => {
|
||||
showToast(t("settings_updated_successfully"), "success");
|
||||
},
|
||||
onError: () => {
|
||||
showToast(t("error_updating_settings"), "error");
|
||||
},
|
||||
onSettled: () => {
|
||||
utils.viewer.organizations.listCurrent.invalidate();
|
||||
},
|
||||
});
|
||||
|
||||
if (!isAdminOrOwner) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsToggle
|
||||
toggleSwitchAtTheEnd={true}
|
||||
title={t("organization_disable_phone_only_sms_notifications_switch_title")}
|
||||
disabled={mutation?.isPending}
|
||||
description={t("organization_disable_phone_only_sms_notifications_switch_description")}
|
||||
checked={disablePhoneOnlySMSNotificationsActive}
|
||||
onCheckedChange={(checked) => {
|
||||
mutation.mutate({
|
||||
disablePhoneOnlySMSNotifications: checked,
|
||||
});
|
||||
setDisablePhoneOnlySMSNotificationsActive(checked);
|
||||
}}
|
||||
switchContainerClassName="mt-6"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -21,6 +21,7 @@ import { Select } from "@calcom/ui/components/form";
|
||||
import { SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui/components/skeleton";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
import { DisablePhoneOnlySMSNotificationsSwitch } from "../components/DisablePhoneOnlySMSNotificationsSwitch";
|
||||
import { LockEventTypeSwitch } from "../components/LockEventTypeSwitch";
|
||||
import { NoSlotsNotificationSwitch } from "../components/NoSlotsNotificationSwitch";
|
||||
|
||||
@@ -82,6 +83,7 @@ const OrgGeneralView = () => {
|
||||
|
||||
<LockEventTypeSwitch currentOrg={currentOrg} isAdminOrOwner={!!isAdminOrOwner} />
|
||||
<NoSlotsNotificationSwitch currentOrg={currentOrg} isAdminOrOwner={!!isAdminOrOwner} />
|
||||
<DisablePhoneOnlySMSNotificationsSwitch currentOrg={currentOrg} isAdminOrOwner={!!isAdminOrOwner} />
|
||||
</LicenseRequired>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -268,6 +268,7 @@ export class OrganizationRepository {
|
||||
allowSEOIndexing: true,
|
||||
orgProfileRedirectsToVerifiedDomain: true,
|
||||
orgAutoAcceptEmail: true,
|
||||
disablePhoneOnlySMSNotifications: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -285,6 +286,7 @@ export class OrganizationRepository {
|
||||
allowSEOIndexing: organizationSettings?.allowSEOIndexing,
|
||||
orgProfileRedirectsToVerifiedDomain: organizationSettings?.orgProfileRedirectsToVerifiedDomain,
|
||||
orgAutoAcceptEmail: organizationSettings?.orgAutoAcceptEmail,
|
||||
disablePhoneOnlySMSNotifications: organizationSettings?.disablePhoneOnlySMSNotifications,
|
||||
},
|
||||
user: {
|
||||
role: membership?.role,
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "OrganizationSettings" ADD COLUMN "disablePhoneOnlySMSNotifications" BOOLEAN NOT NULL DEFAULT false;
|
||||
@@ -175,7 +175,7 @@ model EventType {
|
||||
rescheduleWithSameRoundRobinHost Boolean @default(false)
|
||||
|
||||
secondaryEmailId Int?
|
||||
secondaryEmail SecondaryEmail? @relation(fields: [secondaryEmailId], references: [id], onDelete: Cascade)
|
||||
secondaryEmail SecondaryEmail? @relation(fields: [secondaryEmailId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, slug])
|
||||
@@unique([teamId, slug])
|
||||
@@ -206,12 +206,12 @@ model Credential {
|
||||
paymentStatus String?
|
||||
billingCycleStart Int?
|
||||
|
||||
destinationCalendars DestinationCalendar[]
|
||||
selectedCalendars SelectedCalendar[]
|
||||
invalid Boolean? @default(false)
|
||||
CalendarCache CalendarCache[]
|
||||
references BookingReference[]
|
||||
delegationCredentialId String?
|
||||
destinationCalendars DestinationCalendar[]
|
||||
selectedCalendars SelectedCalendar[]
|
||||
invalid Boolean? @default(false)
|
||||
CalendarCache CalendarCache[]
|
||||
references BookingReference[]
|
||||
delegationCredentialId String?
|
||||
delegationCredential DelegationCredential? @relation(fields: [delegationCredentialId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId])
|
||||
@@ -531,6 +531,7 @@ model OrganizationSettings {
|
||||
isAdminAPIEnabled Boolean @default(false)
|
||||
allowSEOIndexing Boolean @default(false)
|
||||
orgProfileRedirectsToVerifiedDomain Boolean @default(false)
|
||||
disablePhoneOnlySMSNotifications Boolean @default(false)
|
||||
}
|
||||
|
||||
enum MembershipRole {
|
||||
@@ -1467,7 +1468,7 @@ view BookingTimeStatus {
|
||||
model CalendarCache {
|
||||
// To be made required in a followup
|
||||
id String? @default(uuid())
|
||||
|
||||
|
||||
// The key would be the unique URL that is requested by the user
|
||||
key String
|
||||
value Json
|
||||
@@ -1475,9 +1476,10 @@ model CalendarCache {
|
||||
credentialId Int
|
||||
userId Int?
|
||||
credential Credential? @relation(fields: [credentialId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@id([credentialId, key])
|
||||
@@index([userId, key])
|
||||
@@unique([credentialId, key])
|
||||
@@index([userId, key])
|
||||
}
|
||||
|
||||
enum RedirectType {
|
||||
|
||||
@@ -29,12 +29,21 @@ const handleSendingSMS = ({
|
||||
parent: {
|
||||
select: {
|
||||
isOrganization: true,
|
||||
organizationSettings: {
|
||||
select: {
|
||||
disablePhoneOnlySMSNotifications: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!team?.parent?.isOrganization) return;
|
||||
if (
|
||||
!team?.parent?.isOrganization ||
|
||||
team?.parent?.organizationSettings?.disablePhoneOnlySMSNotifications
|
||||
)
|
||||
return;
|
||||
|
||||
await checkSMSRateLimit({ identifier: `handleSendingSMS:team:${teamId}`, rateLimitingType: "sms" });
|
||||
const sms = twilio.sendSMS(reminderPhone, smsMessage, senderID, teamId);
|
||||
|
||||
@@ -49,6 +49,10 @@ const updateOrganizationSettings = async ({
|
||||
data.orgProfileRedirectsToVerifiedDomain = input.orgProfileRedirectsToVerifiedDomain;
|
||||
}
|
||||
|
||||
if (input.hasOwnProperty("disablePhoneOnlySMSNotifications")) {
|
||||
data.disablePhoneOnlySMSNotifications = input.disablePhoneOnlySMSNotifications;
|
||||
}
|
||||
|
||||
// If no settings values have changed lets skip this update
|
||||
if (Object.keys(data).length === 0) return;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ export const ZUpdateInputSchema = z.object({
|
||||
adminGetsNoSlotsNotification: z.boolean().optional(),
|
||||
allowSEOIndexing: z.boolean().optional(),
|
||||
orgProfileRedirectsToVerifiedDomain: z.boolean().optional(),
|
||||
disablePhoneOnlySMSNotifications: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type TUpdateInputSchema = z.infer<typeof ZUpdateInputSchema>;
|
||||
|
||||
Reference in New Issue
Block a user