diff --git a/app/core/components/phone-init-loader.tsx b/app/core/components/phone-init-loader.tsx index e837069..cf92795 100644 --- a/app/core/components/phone-init-loader.tsx +++ b/app/core/components/phone-init-loader.tsx @@ -14,7 +14,7 @@ export default function PhoneInitLoader() { d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" /> -

We're finalizing your cloud phone initialization.

+

We're finalizing your 🐚phone initialization.

You don't have to refresh this page, we will do it automatically for you when your phone is ready.

diff --git a/app/settings/components/phone/phone-number-form.tsx b/app/settings/components/phone/phone-number-form.tsx index 7ee33f5..0208d6c 100644 --- a/app/settings/components/phone/phone-number-form.tsx +++ b/app/settings/components/phone/phone-number-form.tsx @@ -8,6 +8,7 @@ import useCurrentUser from "app/core/hooks/use-current-user"; import useUserPhoneNumber from "app/core/hooks/use-current-phone-number"; import Button from "../button"; import SettingsSection from "../settings-section"; +import Alert from "app/core/components/alert"; type Form = { phoneNumberSid: string; @@ -22,7 +23,7 @@ export default function PhoneNumberForm() { setValue, formState: { isSubmitting }, } = useForm
(); - const [setPhoneNumberMutation] = useMutation(setPhoneNumber); + const [setPhoneNumberMutation, { error, isError, isSuccess }] = useMutation(setPhoneNumber); const [availablePhoneNumbers] = useQuery(getAvailablePhoneNumbers, {}, { enabled: hasFilledTwilioCredentials }); useEffect(() => { @@ -55,6 +56,22 @@ export default function PhoneNumberForm() { } > + {isError ? ( +
+ +
+ ) : null} + + {isSuccess ? ( +
+ +
+ ) : null} + @@ -74,3 +91,15 @@ export default function PhoneNumberForm() {
); } + +function parseErrorMessage(error: Error | null): string { + if (!error) { + return ""; + } + + if (error.name === "ZodError") { + return JSON.parse(error.message)[0].message; + } + + return error.message; +} diff --git a/app/settings/mutations/set-phone-number.ts b/app/settings/mutations/set-phone-number.ts index e7c551e..1baa7de 100644 --- a/app/settings/mutations/set-phone-number.ts +++ b/app/settings/mutations/set-phone-number.ts @@ -1,4 +1,4 @@ -import { resolver } from "blitz"; +import { NotFoundError, resolver } from "blitz"; import { z } from "zod"; import twilio from "twilio"; import RestException from "twilio/lib/base/RestException"; @@ -24,15 +24,35 @@ export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({ organization.twilioAccountSid, organization.twilioAuthToken, ).incomingPhoneNumbers.list(); - const phoneNumber = phoneNumbers.find((phoneNumber) => phoneNumber.sid === phoneNumberSid)!; + const twilioPhoneNumber = phoneNumbers.find((phoneNumber) => phoneNumber.sid === phoneNumberSid); + if (!twilioPhoneNumber) { + throw new NotFoundError(); + } + const organizationId = organization.id; - await db.phoneNumber.create({ - data: { - organizationId, - id: phoneNumberSid, - number: phoneNumber.phoneNumber, - }, - }); + const orgCurrentlyActivePhoneNumber = await db.phoneNumber.findFirst({ where: { organizationId } }); + if (orgCurrentlyActivePhoneNumber) { + // TODO: delete this and allow switching phone numbers easily + await db.phoneNumber.delete({ + where: { + organizationId_id: { + organizationId, + id: orgCurrentlyActivePhoneNumber.id, + }, + }, + }); + } + + const phoneNumber = await db.phoneNumber.findFirst({ where: { id: phoneNumberSid } }); + if (!phoneNumber) { + await db.phoneNumber.create({ + data: { + organizationId, + id: phoneNumberSid, + number: twilioPhoneNumber.phoneNumber, + }, + }); + } let newApiKey; const mainTwilioClient = twilio(organization.twilioAccountSid, organization.twilioAuthToken); @@ -61,7 +81,7 @@ export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({ } const phoneNumberId = phoneNumberSid; - let promises = [ + let promises: Promise[] = [ setTwilioWebhooks.enqueue( { organizationId, phoneNumberId }, { id: `set-twilio-webhooks-${organizationId}-${phoneNumberId}` }, @@ -71,6 +91,14 @@ export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({ const hasActiveSubscription = organization.subscriptions.length > 0; if (hasActiveSubscription) { promises.push( + db.processingPhoneNumber.create({ + data: { + organizationId, + phoneNumberId, + hasFetchedMessages: false, + hasFetchedCalls: false, + }, + }), fetchMessagesQueue.enqueue( { organizationId, phoneNumberId }, { id: `fetch-messages-${organizationId}-${phoneNumberId}` }, diff --git a/app/settings/mutations/set-twilio-api-fields.ts b/app/settings/mutations/set-twilio-api-fields.ts index 26d6fe5..fb31cc7 100644 --- a/app/settings/mutations/set-twilio-api-fields.ts +++ b/app/settings/mutations/set-twilio-api-fields.ts @@ -26,17 +26,5 @@ export default resolver.pipe( twilioAuthToken: twilioAuthToken, }, }); - - const phoneNumber = await db.phoneNumber.findFirst({ where: { organizationId } }); - if (phoneNumber) { - await db.phoneNumber.delete({ - where: { - organizationId_id: { - organizationId, - id: phoneNumber.id, - }, - }, - }); - } }, );