send notification when sms arrives

This commit is contained in:
m5r
2021-08-02 00:28:47 +08:00
parent 1489f97c14
commit fef4c03458
14 changed files with 1834 additions and 25 deletions

View File

@ -0,0 +1,59 @@
import { getConfig } from "blitz";
import { Queue } from "quirrel/blitz";
import type { MessageInstance } from "twilio/lib/rest/api/v2010/account/message";
import twilio from "twilio";
import webpush, { PushSubscription, WebPushError } from "web-push";
import db from "../../../../db";
import appLogger from "../../../../integrations/logger";
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig();
const logger = appLogger.child({ queue: "notify-incoming-message" });
type Payload = {
customerId: string;
messageSid: MessageInstance["sid"];
};
const notifyIncomingMessageQueue = Queue<Payload>(
"api/queue/notify-incoming-message",
async ({ messageSid, customerId }) => {
webpush.setVapidDetails(
"mailto:mokht@rmi.al",
publicRuntimeConfig.webPush.publicKey,
serverRuntimeConfig.webPush.privateKey,
);
const customer = await db.customer.findFirst({ where: { id: customerId } });
if (!customer || !customer.accountSid || !customer.authToken) {
return;
}
const message = await twilio(customer.accountSid, customer.authToken).messages.get(messageSid).fetch();
const notification = { message: `${message.from} - ${message.body}` };
const subscriptions = await db.notificationSubscription.findMany({ where: { customerId: customer.id } });
await Promise.all(
subscriptions.map(async (subscription) => {
const webPushSubscription: PushSubscription = {
endpoint: subscription.endpoint,
keys: {
p256dh: subscription.keys_p256dh,
auth: subscription.keys_auth,
},
};
try {
await webpush.sendNotification(webPushSubscription, JSON.stringify(notification));
} catch (error) {
logger.error(error);
if (error instanceof WebPushError) {
// subscription most likely expired
await db.notificationSubscription.delete({ where: { id: subscription.id } });
}
}
}),
);
},
);
export default notifyIncomingMessageQueue;

View File

@ -6,6 +6,7 @@ import type { ApiError } from "../../../api/_types";
import appLogger from "../../../../integrations/logger";
import db from "../../../../db";
import insertIncomingMessageQueue from "../queue/insert-incoming-message";
import notifyIncomingMessageQueue from "../queue/notify-incoming-message";
const logger = appLogger.child({ route: "/api/webhook/incoming-message" });
const { serverRuntimeConfig } = getConfig();
@ -70,16 +71,24 @@ export default async function incomingMessageHandler(req: BlitzApiRequest, res:
return;
}
// TODO: send notification
const messageSid = body.MessageSid;
await insertIncomingMessageQueue.enqueue(
{
messageSid,
customerId: customer.id,
},
{ id: messageSid },
);
const customerId = customer.id;
await Promise.all([
notifyIncomingMessageQueue.enqueue(
{
messageSid,
customerId,
},
{ id: `notify-${messageSid}` },
),
insertIncomingMessageQueue.enqueue(
{
messageSid,
customerId,
},
{ id: `insert-${messageSid}` },
),
]);
res.status(200).end();
} catch (error) {

View File

@ -48,7 +48,7 @@ export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({
content,
},
{
id: message.id,
id: `insert-${message.id}`,
},
);
});

View File

@ -1,4 +1,4 @@
import { Suspense } from "react";
import { Suspense, useEffect } from "react";
import type { BlitzPage } from "blitz";
import { Routes } from "blitz";
import { useAtom } from "jotai";
@ -8,11 +8,19 @@ import ConversationsList from "../components/conversations-list";
import NewMessageButton from "../components/new-message-button";
import NewMessageBottomSheet, { bottomSheetOpenAtom } from "../components/new-message-bottom-sheet";
import useRequireOnboarding from "../../core/hooks/use-require-onboarding";
import useNotifications from "../../core/hooks/use-notifications";
const Messages: BlitzPage = () => {
useRequireOnboarding();
const { subscription, subscribe } = useNotifications();
const setIsOpen = useAtom(bottomSheetOpenAtom)[1];
useEffect(() => {
if (!subscription) {
subscribe();
}
}, [subscription?.endpoint]);
return (
<>
<div className="flex flex-col space-y-6 p-6">