reformat with prettier with semicolons and tabs
This commit is contained in:
@ -1,67 +1,67 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
import twilio from "twilio"
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import twilio from "twilio";
|
||||
|
||||
import type { ApiError } from "../../../api/_types"
|
||||
import appLogger from "../../../../integrations/logger"
|
||||
import { encrypt } from "../../../../db/_encryption"
|
||||
import db, { Direction, MessageStatus } from "../../../../db"
|
||||
import { MessageInstance } from "twilio/lib/rest/api/v2010/account/message"
|
||||
import type { ApiError } from "../../../api/_types";
|
||||
import appLogger from "../../../../integrations/logger";
|
||||
import { encrypt } from "../../../../db/_encryption";
|
||||
import db, { Direction, MessageStatus } from "../../../../db";
|
||||
import { MessageInstance } from "twilio/lib/rest/api/v2010/account/message";
|
||||
|
||||
const logger = appLogger.child({ route: "/api/webhook/incoming-message" })
|
||||
const logger = appLogger.child({ route: "/api/webhook/incoming-message" });
|
||||
|
||||
export default async function incomingMessageHandler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method !== "POST") {
|
||||
const statusCode = 405
|
||||
const statusCode = 405;
|
||||
const apiError: ApiError = {
|
||||
statusCode,
|
||||
errorMessage: `Method ${req.method} Not Allowed`,
|
||||
}
|
||||
logger.error(apiError)
|
||||
};
|
||||
logger.error(apiError);
|
||||
|
||||
res.setHeader("Allow", ["POST"])
|
||||
res.status(statusCode).send(apiError)
|
||||
return
|
||||
res.setHeader("Allow", ["POST"]);
|
||||
res.status(statusCode).send(apiError);
|
||||
return;
|
||||
}
|
||||
|
||||
const twilioSignature = req.headers["X-Twilio-Signature"] || req.headers["x-twilio-signature"]
|
||||
const twilioSignature = req.headers["X-Twilio-Signature"] || req.headers["x-twilio-signature"];
|
||||
if (!twilioSignature || Array.isArray(twilioSignature)) {
|
||||
const statusCode = 400
|
||||
const statusCode = 400;
|
||||
const apiError: ApiError = {
|
||||
statusCode,
|
||||
errorMessage: "Invalid header X-Twilio-Signature",
|
||||
}
|
||||
logger.error(apiError)
|
||||
};
|
||||
logger.error(apiError);
|
||||
|
||||
res.status(statusCode).send(apiError)
|
||||
return
|
||||
res.status(statusCode).send(apiError);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("req.body", req.body)
|
||||
console.log("req.body", req.body);
|
||||
try {
|
||||
const phoneNumber = req.body.To
|
||||
const phoneNumber = req.body.To;
|
||||
const customerPhoneNumber = await db.phoneNumber.findFirst({
|
||||
where: { phoneNumber },
|
||||
})
|
||||
});
|
||||
const customer = await db.customer.findFirst({
|
||||
where: { id: customerPhoneNumber!.customerId },
|
||||
})
|
||||
const url = "https://phone.mokhtar.dev/api/webhook/incoming-message"
|
||||
});
|
||||
const url = "https://phone.mokhtar.dev/api/webhook/incoming-message";
|
||||
const isRequestValid = twilio.validateRequest(
|
||||
customer!.authToken!,
|
||||
twilioSignature,
|
||||
url,
|
||||
req.body
|
||||
)
|
||||
);
|
||||
if (!isRequestValid) {
|
||||
const statusCode = 400
|
||||
const statusCode = 400;
|
||||
const apiError: ApiError = {
|
||||
statusCode,
|
||||
errorMessage: "Invalid webhook",
|
||||
}
|
||||
logger.error(apiError)
|
||||
};
|
||||
logger.error(apiError);
|
||||
|
||||
res.status(statusCode).send(apiError)
|
||||
return
|
||||
res.status(statusCode).send(apiError);
|
||||
return;
|
||||
}
|
||||
|
||||
await db.message.create({
|
||||
@ -74,58 +74,58 @@ export default async function incomingMessageHandler(req: NextApiRequest, res: N
|
||||
sentAt: req.body.DateSent,
|
||||
content: encrypt(req.body.Body, customer!.encryptionKey),
|
||||
},
|
||||
})
|
||||
});
|
||||
} catch (error) {
|
||||
const statusCode = error.statusCode ?? 500
|
||||
const statusCode = error.statusCode ?? 500;
|
||||
const apiError: ApiError = {
|
||||
statusCode,
|
||||
errorMessage: error.message,
|
||||
}
|
||||
logger.error(error)
|
||||
};
|
||||
logger.error(error);
|
||||
|
||||
res.status(statusCode).send(apiError)
|
||||
res.status(statusCode).send(apiError);
|
||||
}
|
||||
}
|
||||
|
||||
function translateDirection(direction: MessageInstance["direction"]): Direction {
|
||||
switch (direction) {
|
||||
case "inbound":
|
||||
return Direction.Inbound
|
||||
return Direction.Inbound;
|
||||
case "outbound-api":
|
||||
case "outbound-call":
|
||||
case "outbound-reply":
|
||||
default:
|
||||
return Direction.Outbound
|
||||
return Direction.Outbound;
|
||||
}
|
||||
}
|
||||
|
||||
function translateStatus(status: MessageInstance["status"]): MessageStatus {
|
||||
switch (status) {
|
||||
case "accepted":
|
||||
return MessageStatus.Accepted
|
||||
return MessageStatus.Accepted;
|
||||
case "canceled":
|
||||
return MessageStatus.Canceled
|
||||
return MessageStatus.Canceled;
|
||||
case "delivered":
|
||||
return MessageStatus.Delivered
|
||||
return MessageStatus.Delivered;
|
||||
case "failed":
|
||||
return MessageStatus.Failed
|
||||
return MessageStatus.Failed;
|
||||
case "partially_delivered":
|
||||
return MessageStatus.PartiallyDelivered
|
||||
return MessageStatus.PartiallyDelivered;
|
||||
case "queued":
|
||||
return MessageStatus.Queued
|
||||
return MessageStatus.Queued;
|
||||
case "read":
|
||||
return MessageStatus.Read
|
||||
return MessageStatus.Read;
|
||||
case "received":
|
||||
return MessageStatus.Received
|
||||
return MessageStatus.Received;
|
||||
case "receiving":
|
||||
return MessageStatus.Receiving
|
||||
return MessageStatus.Receiving;
|
||||
case "scheduled":
|
||||
return MessageStatus.Scheduled
|
||||
return MessageStatus.Scheduled;
|
||||
case "sending":
|
||||
return MessageStatus.Sending
|
||||
return MessageStatus.Sending;
|
||||
case "sent":
|
||||
return MessageStatus.Sent
|
||||
return MessageStatus.Sent;
|
||||
case "undelivered":
|
||||
return MessageStatus.Undelivered
|
||||
return MessageStatus.Undelivered;
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,37 @@
|
||||
import { Suspense, useEffect, useRef } from "react"
|
||||
import { useRouter } from "blitz"
|
||||
import clsx from "clsx"
|
||||
import { Suspense, useEffect, useRef } from "react";
|
||||
import { useRouter } from "blitz";
|
||||
import clsx from "clsx";
|
||||
|
||||
import { Direction } from "../../../db"
|
||||
import useConversation from "../hooks/use-conversation"
|
||||
import NewMessageArea from "./new-message-area"
|
||||
import { Direction } from "../../../db";
|
||||
import useConversation from "../hooks/use-conversation";
|
||||
import NewMessageArea from "./new-message-area";
|
||||
|
||||
export default function Conversation() {
|
||||
const router = useRouter()
|
||||
const conversation = useConversation(router.params.recipient)[0]
|
||||
const messagesListRef = useRef<HTMLUListElement>(null)
|
||||
const router = useRouter();
|
||||
const conversation = useConversation(router.params.recipient)[0];
|
||||
const messagesListRef = useRef<HTMLUListElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
messagesListRef.current?.querySelector("li:last-child")?.scrollIntoView()
|
||||
}, [conversation, messagesListRef])
|
||||
messagesListRef.current?.querySelector("li:last-child")?.scrollIntoView();
|
||||
}, [conversation, messagesListRef]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col space-y-6 p-6 pt-12 pb-16">
|
||||
<ul ref={messagesListRef}>
|
||||
{conversation.map((message, index) => {
|
||||
const isOutbound = message.direction === Direction.Outbound
|
||||
const nextMessage = conversation![index + 1]
|
||||
const previousMessage = conversation![index - 1]
|
||||
const isSameNext = message.from === nextMessage?.from
|
||||
const isSamePrevious = message.from === previousMessage?.from
|
||||
const isOutbound = message.direction === Direction.Outbound;
|
||||
const nextMessage = conversation![index + 1];
|
||||
const previousMessage = conversation![index - 1];
|
||||
const isSameNext = message.from === nextMessage?.from;
|
||||
const isSamePrevious = message.from === previousMessage?.from;
|
||||
const differenceInMinutes = previousMessage
|
||||
? (new Date(message.sentAt).getTime() -
|
||||
new Date(previousMessage.sentAt).getTime()) /
|
||||
1000 /
|
||||
60
|
||||
: 0
|
||||
const isTooLate = differenceInMinutes > 15
|
||||
: 0;
|
||||
const isTooLate = differenceInMinutes > 15;
|
||||
return (
|
||||
<li key={message.id}>
|
||||
{(!isSamePrevious || isTooLate) && (
|
||||
@ -70,7 +70,7 @@ export default function Conversation() {
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
@ -78,5 +78,5 @@ export default function Conversation() {
|
||||
<NewMessageArea />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
import { Link, useQuery } from "blitz"
|
||||
import { Link, useQuery } from "blitz";
|
||||
|
||||
import getConversationsQuery from "../queries/get-conversations"
|
||||
import getConversationsQuery from "../queries/get-conversations";
|
||||
|
||||
export default function ConversationsList() {
|
||||
const conversations = useQuery(getConversationsQuery, {})[0]
|
||||
const conversations = useQuery(getConversationsQuery, {})[0];
|
||||
|
||||
if (Object.keys(conversations).length === 0) {
|
||||
return <div>empty state</div>
|
||||
return <div>empty state</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className="divide-y">
|
||||
{Object.entries(conversations).map(([recipient, messages]) => {
|
||||
const lastMessage = messages[messages.length - 1]!
|
||||
const lastMessage = messages[messages.length - 1]!;
|
||||
return (
|
||||
<li key={recipient} className="py-2">
|
||||
<Link href={`/messages/${encodeURIComponent(recipient)}`}>
|
||||
@ -27,8 +27,8 @@ export default function ConversationsList() {
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1,40 +1,40 @@
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
import { faPaperPlane } from "@fortawesome/pro-regular-svg-icons"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useMutation, useQuery, useRouter } from "blitz"
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faPaperPlane } from "@fortawesome/pro-regular-svg-icons";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useMutation, useQuery, useRouter } from "blitz";
|
||||
|
||||
import sendMessage from "../mutations/send-message"
|
||||
import { Direction, Message, MessageStatus } from "../../../db"
|
||||
import getConversationsQuery from "../queries/get-conversations"
|
||||
import useCurrentCustomer from "../../core/hooks/use-current-customer"
|
||||
import useCustomerPhoneNumber from "../../core/hooks/use-customer-phone-number"
|
||||
import sendMessage from "../mutations/send-message";
|
||||
import { Direction, Message, MessageStatus } from "../../../db";
|
||||
import getConversationsQuery from "../queries/get-conversations";
|
||||
import useCurrentCustomer from "../../core/hooks/use-current-customer";
|
||||
import useCustomerPhoneNumber from "../../core/hooks/use-customer-phone-number";
|
||||
|
||||
type Form = {
|
||||
content: string
|
||||
}
|
||||
content: string;
|
||||
};
|
||||
|
||||
export default function NewMessageArea() {
|
||||
const router = useRouter()
|
||||
const recipient = router.params.recipient
|
||||
const { customer } = useCurrentCustomer()
|
||||
const phoneNumber = useCustomerPhoneNumber()
|
||||
const sendMessageMutation = useMutation(sendMessage)[0]
|
||||
const router = useRouter();
|
||||
const recipient = router.params.recipient;
|
||||
const { customer } = useCurrentCustomer();
|
||||
const phoneNumber = useCustomerPhoneNumber();
|
||||
const sendMessageMutation = useMutation(sendMessage)[0];
|
||||
const { setQueryData: setConversationsQueryData, refetch: refetchConversations } = useQuery(
|
||||
getConversationsQuery,
|
||||
{}
|
||||
)[1]
|
||||
)[1];
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { isSubmitting },
|
||||
} = useForm<Form>()
|
||||
} = useForm<Form>();
|
||||
const onSubmit = handleSubmit(async ({ content }) => {
|
||||
if (isSubmitting) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const id = uuidv4()
|
||||
const id = uuidv4();
|
||||
const message: Message = {
|
||||
id,
|
||||
customerId: customer!.id,
|
||||
@ -45,24 +45,24 @@ export default function NewMessageArea() {
|
||||
direction: Direction.Outbound,
|
||||
status: MessageStatus.Queued,
|
||||
sentAt: new Date(),
|
||||
}
|
||||
};
|
||||
|
||||
await setConversationsQueryData(
|
||||
(conversations) => {
|
||||
const nextConversations = { ...conversations }
|
||||
const nextConversations = { ...conversations };
|
||||
if (!nextConversations[recipient]) {
|
||||
nextConversations[recipient] = []
|
||||
nextConversations[recipient] = [];
|
||||
}
|
||||
|
||||
nextConversations[recipient] = [...nextConversations[recipient]!, message]
|
||||
return nextConversations
|
||||
nextConversations[recipient] = [...nextConversations[recipient]!, message];
|
||||
return nextConversations;
|
||||
},
|
||||
{ refetch: false }
|
||||
)
|
||||
setValue("content", "")
|
||||
await sendMessageMutation({ to: recipient, content })
|
||||
await refetchConversations({ cancelRefetch: true })
|
||||
})
|
||||
);
|
||||
setValue("content", "");
|
||||
await sendMessageMutation({ to: recipient, content });
|
||||
await refetchConversations({ cancelRefetch: true });
|
||||
});
|
||||
|
||||
return (
|
||||
<form
|
||||
@ -82,13 +82,13 @@ export default function NewMessageArea() {
|
||||
<FontAwesomeIcon size="2x" className="h-8 w-8 pl-1 pr-2" icon={faPaperPlane} />
|
||||
</button>
|
||||
</form>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function uuidv4() {
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
||||
const r = (Math.random() * 16) | 0,
|
||||
v = c == "x" ? r : (r & 0x3) | 0x8
|
||||
return v.toString(16)
|
||||
})
|
||||
v = c == "x" ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useQuery } from "blitz"
|
||||
import { useQuery } from "blitz";
|
||||
|
||||
import getConversationsQuery from "../queries/get-conversations"
|
||||
import getConversationsQuery from "../queries/get-conversations";
|
||||
|
||||
export default function useConversation(recipient: string) {
|
||||
return useQuery(
|
||||
@ -9,11 +9,11 @@ export default function useConversation(recipient: string) {
|
||||
{
|
||||
select(conversations) {
|
||||
if (!conversations[recipient]) {
|
||||
throw new Error("Conversation not found")
|
||||
throw new Error("Conversation not found");
|
||||
}
|
||||
|
||||
return conversations[recipient]!
|
||||
return conversations[recipient]!;
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
import { resolver } from "blitz"
|
||||
import { z } from "zod"
|
||||
import { resolver } from "blitz";
|
||||
import { z } from "zod";
|
||||
|
||||
import db, { Direction, MessageStatus } from "../../../db"
|
||||
import getCurrentCustomer from "../../customers/queries/get-current-customer"
|
||||
import getCustomerPhoneNumber from "../../phone-numbers/queries/get-customer-phone-number"
|
||||
import { encrypt } from "../../../db/_encryption"
|
||||
import sendMessageQueue from "../../api/queue/send-message"
|
||||
import db, { Direction, MessageStatus } from "../../../db";
|
||||
import getCurrentCustomer from "../../customers/queries/get-current-customer";
|
||||
import getCustomerPhoneNumber from "../../phone-numbers/queries/get-customer-phone-number";
|
||||
import { encrypt } from "../../../db/_encryption";
|
||||
import sendMessageQueue from "../../api/queue/send-message";
|
||||
|
||||
const Body = z.object({
|
||||
content: z.string(),
|
||||
to: z.string(),
|
||||
})
|
||||
});
|
||||
|
||||
export default resolver.pipe(
|
||||
resolver.zod(Body),
|
||||
resolver.authorize(),
|
||||
async ({ content, to }, context) => {
|
||||
const customer = await getCurrentCustomer(null, context)
|
||||
const customerId = customer!.id
|
||||
const customerPhoneNumber = await getCustomerPhoneNumber({ customerId }, context)
|
||||
const customer = await getCurrentCustomer(null, context);
|
||||
const customerId = customer!.id;
|
||||
const customerPhoneNumber = await getCustomerPhoneNumber({ customerId }, context);
|
||||
|
||||
const message = await db.message.create({
|
||||
data: {
|
||||
@ -30,7 +30,7 @@ export default resolver.pipe(
|
||||
content: encrypt(content, customer!.encryptionKey),
|
||||
sentAt: new Date(),
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
await sendMessageQueue.enqueue(
|
||||
{
|
||||
@ -42,6 +42,6 @@ export default resolver.pipe(
|
||||
{
|
||||
id: message.id,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Suspense } from "react"
|
||||
import type { BlitzPage } from "blitz"
|
||||
import { Suspense } from "react";
|
||||
import type { BlitzPage } from "blitz";
|
||||
|
||||
import Layout from "../../core/layouts/layout"
|
||||
import ConversationsList from "../components/conversations-list"
|
||||
import useRequireOnboarding from "../../core/hooks/use-require-onboarding"
|
||||
import Layout from "../../core/layouts/layout";
|
||||
import ConversationsList from "../components/conversations-list";
|
||||
import useRequireOnboarding from "../../core/hooks/use-require-onboarding";
|
||||
|
||||
const Messages: BlitzPage = () => {
|
||||
useRequireOnboarding()
|
||||
useRequireOnboarding();
|
||||
|
||||
return (
|
||||
<Layout title="Messages">
|
||||
@ -17,9 +17,9 @@ const Messages: BlitzPage = () => {
|
||||
<ConversationsList />
|
||||
</Suspense>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
Messages.authenticate = true
|
||||
Messages.authenticate = true;
|
||||
|
||||
export default Messages
|
||||
export default Messages;
|
||||
|
@ -1,19 +1,22 @@
|
||||
import { Suspense } from "react"
|
||||
import { BlitzPage, useRouter } from "blitz"
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
import { Suspense } from "react";
|
||||
import { BlitzPage, useRouter } from "blitz";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faLongArrowLeft,
|
||||
faInfoCircle,
|
||||
faPhoneAlt as faPhone,
|
||||
} from "@fortawesome/pro-regular-svg-icons"
|
||||
} from "@fortawesome/pro-regular-svg-icons";
|
||||
|
||||
import Layout from "../../../core/layouts/layout"
|
||||
import Conversation from "../../components/conversation"
|
||||
import Layout from "../../../core/layouts/layout";
|
||||
import Conversation from "../../components/conversation";
|
||||
import useRequireOnboarding from "../../../core/hooks/use-require-onboarding";
|
||||
|
||||
const ConversationPage: BlitzPage = () => {
|
||||
const router = useRouter()
|
||||
const recipient = router.params.recipient
|
||||
const pageTitle = `Messages with ${recipient}`
|
||||
useRequireOnboarding();
|
||||
|
||||
const router = useRouter();
|
||||
const recipient = router.params.recipient;
|
||||
const pageTitle = `Messages with ${recipient}`;
|
||||
|
||||
return (
|
||||
<Layout title={pageTitle} hideFooter>
|
||||
@ -31,9 +34,9 @@ const ConversationPage: BlitzPage = () => {
|
||||
<Conversation />
|
||||
</Suspense>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
ConversationPage.authenticate = true
|
||||
ConversationPage.authenticate = true;
|
||||
|
||||
export default ConversationPage
|
||||
export default ConversationPage;
|
||||
|
@ -1,31 +1,31 @@
|
||||
import { resolver } from "blitz"
|
||||
import { z } from "zod"
|
||||
import { resolver } from "blitz";
|
||||
import { z } from "zod";
|
||||
|
||||
import db, { Prisma } from "../../../db"
|
||||
import { decrypt } from "../../../db/_encryption"
|
||||
import getCurrentCustomer from "../../customers/queries/get-current-customer"
|
||||
import db, { Prisma } from "../../../db";
|
||||
import { decrypt } from "../../../db/_encryption";
|
||||
import getCurrentCustomer from "../../customers/queries/get-current-customer";
|
||||
|
||||
const GetConversations = z.object({
|
||||
recipient: z.string(),
|
||||
})
|
||||
});
|
||||
|
||||
export default resolver.pipe(
|
||||
resolver.zod(GetConversations),
|
||||
resolver.authorize(),
|
||||
async ({ recipient }, context) => {
|
||||
const customer = await getCurrentCustomer(null, context)
|
||||
const customer = await getCurrentCustomer(null, context);
|
||||
const conversation = await db.message.findMany({
|
||||
where: {
|
||||
OR: [{ from: recipient }, { to: recipient }],
|
||||
},
|
||||
orderBy: { sentAt: Prisma.SortOrder.asc },
|
||||
})
|
||||
});
|
||||
|
||||
return conversation.map((message) => {
|
||||
return {
|
||||
...message,
|
||||
content: decrypt(message.content, customer!.encryptionKey),
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -1,41 +1,41 @@
|
||||
import { resolver } from "blitz"
|
||||
import { resolver } from "blitz";
|
||||
|
||||
import db, { Direction, Message, Prisma } from "../../../db"
|
||||
import getCurrentCustomer from "../../customers/queries/get-current-customer"
|
||||
import { decrypt } from "../../../db/_encryption"
|
||||
import db, { Direction, Message, Prisma } from "../../../db";
|
||||
import getCurrentCustomer from "../../customers/queries/get-current-customer";
|
||||
import { decrypt } from "../../../db/_encryption";
|
||||
|
||||
export default resolver.pipe(resolver.authorize(), async (_ = null, context) => {
|
||||
const customer = await getCurrentCustomer(null, context)
|
||||
const customer = await getCurrentCustomer(null, context);
|
||||
const messages = await db.message.findMany({
|
||||
where: { customerId: customer!.id },
|
||||
orderBy: { sentAt: Prisma.SortOrder.asc },
|
||||
})
|
||||
});
|
||||
|
||||
let conversations: Record<string, Message[]> = {}
|
||||
let conversations: Record<string, Message[]> = {};
|
||||
for (const message of messages) {
|
||||
let recipient: string
|
||||
let recipient: string;
|
||||
if (message.direction === Direction.Outbound) {
|
||||
recipient = message.to
|
||||
recipient = message.to;
|
||||
} else {
|
||||
recipient = message.from
|
||||
recipient = message.from;
|
||||
}
|
||||
|
||||
if (!conversations[recipient]) {
|
||||
conversations[recipient] = []
|
||||
conversations[recipient] = [];
|
||||
}
|
||||
|
||||
conversations[recipient]!.push({
|
||||
...message,
|
||||
content: decrypt(message.content, customer!.encryptionKey),
|
||||
})
|
||||
});
|
||||
|
||||
conversations[recipient]!.sort((a, b) => a.sentAt.getTime() - b.sentAt.getTime())
|
||||
conversations[recipient]!.sort((a, b) => a.sentAt.getTime() - b.sentAt.getTime());
|
||||
}
|
||||
conversations = Object.fromEntries(
|
||||
Object.entries(conversations).sort(
|
||||
([, a], [, b]) => b[b.length - 1]!.sentAt.getTime() - a[a.length - 1]!.sentAt.getTime()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return conversations
|
||||
})
|
||||
return conversations;
|
||||
});
|
||||
|
Reference in New Issue
Block a user