feature/IO-3000-messaging-sockets-migrations2 - Base cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -1,11 +1,6 @@
|
|||||||
import { useApolloClient } from "@apollo/client";
|
import { useApolloClient } from "@apollo/client";
|
||||||
import { getToken, onMessage } from "@firebase/messaging";
|
|
||||||
import { Button, notification, Space } from "antd";
|
|
||||||
import axios from "axios";
|
|
||||||
import React, { useContext, useEffect } from "react";
|
import React, { useContext, useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { messaging, requestForToken } from "../../firebase/firebase.utils";
|
|
||||||
import FcmHandler from "../../utils/fcm-handler";
|
|
||||||
import ChatPopupComponent from "../chat-popup/chat-popup.component";
|
import ChatPopupComponent from "../chat-popup/chat-popup.component";
|
||||||
import "./chat-affix.styles.scss";
|
import "./chat-affix.styles.scss";
|
||||||
import SocketContext from "../../contexts/SocketIO/socketContext";
|
import SocketContext from "../../contexts/SocketIO/socketContext";
|
||||||
@@ -20,81 +15,17 @@ export function ChatAffixContainer({ bodyshop, chatVisible }) {
|
|||||||
if (!bodyshop || !bodyshop.messagingservicesid) return;
|
if (!bodyshop || !bodyshop.messagingservicesid) return;
|
||||||
|
|
||||||
//Register WS handlers
|
//Register WS handlers
|
||||||
registerMessagingHandlers({ socket, client });
|
if (socket && socket.connected) {
|
||||||
|
registerMessagingHandlers({ socket, client });
|
||||||
async function SubscribeToTopic() {
|
|
||||||
try {
|
|
||||||
const r = await axios.post("/notifications/subscribe", {
|
|
||||||
fcm_tokens: await getToken(messaging, {
|
|
||||||
vapidKey: import.meta.env.VITE_APP_FIREBASE_PUBLIC_VAPID_KEY
|
|
||||||
}),
|
|
||||||
type: "messaging",
|
|
||||||
imexshopid: bodyshop.imexshopid
|
|
||||||
});
|
|
||||||
console.log("FCM Topic Subscription", r.data);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error attempting to subscribe to messaging topic: ", error);
|
|
||||||
notification.open({
|
|
||||||
key: "fcm",
|
|
||||||
type: "warning",
|
|
||||||
message: t("general.errors.fcm"),
|
|
||||||
btn: (
|
|
||||||
<Space>
|
|
||||||
<Button
|
|
||||||
onClick={async () => {
|
|
||||||
await requestForToken();
|
|
||||||
SubscribeToTopic();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t("general.actions.tryagain")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
const win = window.open(
|
|
||||||
"https://help.imex.online/en/article/enabling-notifications-o978xi/",
|
|
||||||
"_blank"
|
|
||||||
);
|
|
||||||
win.focus();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t("general.labels.help")}
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SubscribeToTopic();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unregisterMessagingHandlers({ socket });
|
if (socket && socket.connected) {
|
||||||
|
unregisterMessagingHandlers({ socket });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [bodyshop, socket, t, client]);
|
}, [bodyshop, socket, t, client]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
function handleMessage(payload) {
|
|
||||||
FcmHandler({
|
|
||||||
client,
|
|
||||||
payload: (payload && payload.data && payload.data.data) || payload.data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let stopMessageListener, channel;
|
|
||||||
try {
|
|
||||||
stopMessageListener = onMessage(messaging, handleMessage);
|
|
||||||
channel = new BroadcastChannel("imex-sw-messages");
|
|
||||||
channel.addEventListener("message", handleMessage);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Unable to set event listeners.");
|
|
||||||
}
|
|
||||||
return () => {
|
|
||||||
stopMessageListener && stopMessageListener();
|
|
||||||
channel && channel.removeEventListener("message", handleMessage);
|
|
||||||
};
|
|
||||||
}, [client]);
|
|
||||||
|
|
||||||
if (!bodyshop || !bodyshop.messagingservicesid) return <></>;
|
if (!bodyshop || !bodyshop.messagingservicesid) return <></>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { CONVERSATION_LIST_QUERY, GET_CONVERSATION_DETAILS } from "../../graphql/conversations.queries";
|
import { CONVERSATION_LIST_QUERY, GET_CONVERSATION_DETAILS } from "../../graphql/conversations.queries";
|
||||||
|
|
||||||
export function registerMessagingHandlers({ socket, client }) {
|
export const registerMessagingHandlers = ({ socket, client }) => {
|
||||||
if (!(socket && client)) return;
|
if (!(socket && client)) return;
|
||||||
function handleNewMessageSummary(message) {
|
|
||||||
|
const handleNewMessageSummary = (message) => {
|
||||||
console.log("🚀 ~ SUMMARY CONSOLE LOG:", message);
|
console.log("🚀 ~ SUMMARY CONSOLE LOG:", message);
|
||||||
|
|
||||||
if (!message.isoutbound) {
|
if (!message.isoutbound) {
|
||||||
@@ -69,9 +70,9 @@ export function registerMessagingHandlers({ socket, client }) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function handleNewMessageDetailed(message) {
|
const handleNewMessageDetailed = (message) => {
|
||||||
console.log("🚀 ~ DETAIL CONSOLE LOG:", message);
|
console.log("🚀 ~ DETAIL CONSOLE LOG:", message);
|
||||||
//They're looking at the conversation right now. Need to merge into the list of messages i.e. append to the end.
|
//They're looking at the conversation right now. Need to merge into the list of messages i.e. append to the end.
|
||||||
//Add the message to the overall cache.
|
//Add the message to the overall cache.
|
||||||
@@ -97,9 +98,9 @@ export function registerMessagingHandlers({ socket, client }) {
|
|||||||
// We got this as a receive.
|
// We got this as a receive.
|
||||||
else {
|
else {
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function handleMessageChanged(message) {
|
const handleMessageChanged = (message) => {
|
||||||
//Find it in the cache, and just update it based on what was sent.
|
//Find it in the cache, and just update it based on what was sent.
|
||||||
client.cache.modify({
|
client.cache.modify({
|
||||||
id: client.cache.identify({
|
id: client.cache.identify({
|
||||||
@@ -114,23 +115,23 @@ export function registerMessagingHandlers({ socket, client }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function handleConversationChanged(conversation) {
|
const handleConversationChanged = (conversation) => {
|
||||||
//If it was archived, marked unread, etc.
|
//If it was archived, marked unread, etc.
|
||||||
}
|
};
|
||||||
|
|
||||||
socket.on("new-message-summary", handleNewMessageSummary);
|
socket.on("new-message-summary", handleNewMessageSummary);
|
||||||
socket.on("new-message-detailed", handleNewMessageDetailed);
|
socket.on("new-message-detailed", handleNewMessageDetailed);
|
||||||
socket.on("message-changed", handleMessageChanged);
|
socket.on("message-changed", handleMessageChanged);
|
||||||
socket.on("conversation-changed", handleConversationChanged); //TODO: Unread, mark as read, archived, unarchive, etc.
|
socket.on("conversation-changed", handleConversationChanged); //TODO: Unread, mark as read, archived, unarchive, etc.
|
||||||
}
|
};
|
||||||
|
|
||||||
export function unregisterMessagingHandlers({ socket }) {
|
export const unregisterMessagingHandlers = ({ socket }) => {
|
||||||
if (!socket) return;
|
if (!socket) return;
|
||||||
socket.off("new-message-summary");
|
socket.off("new-message-summary");
|
||||||
socket.off("new-message-detailed");
|
socket.off("new-message-detailed");
|
||||||
socket.off("message-changed");
|
socket.off("message-changed");
|
||||||
socket.off("message-changed");
|
socket.off("message-changed");
|
||||||
socket.off("conversation-changed");
|
socket.off("conversation-changed");
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { useMutation, useQuery } from "@apollo/client";
|
import { useQuery } from "@apollo/client";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import React, { useEffect, useState, useContext } from "react";
|
import React, { useContext, useEffect, useState } from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import SocketContext from "../../contexts/SocketIO/socketContext";
|
import SocketContext from "../../contexts/SocketIO/socketContext";
|
||||||
import { GET_CONVERSATION_DETAILS } from "../../graphql/conversations.queries";
|
import { GET_CONVERSATION_DETAILS } from "../../graphql/conversations.queries";
|
||||||
import { MARK_MESSAGES_AS_READ_BY_CONVERSATION } from "../../graphql/messages.queries";
|
|
||||||
import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors";
|
import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import ChatConversationComponent from "./chat-conversation.component";
|
import ChatConversationComponent from "./chat-conversation.component";
|
||||||
@@ -31,10 +30,16 @@ export function ChatConversationContainer({ bodyshop, selectedConversation }) {
|
|||||||
const { socket } = useContext(SocketContext);
|
const { socket } = useContext(SocketContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
socket.emit("join-bodyshop-conversation", { bodyshopId: bodyshop.id, conversationId: selectedConversation });
|
socket.emit("join-bodyshop-conversation", {
|
||||||
|
bodyshopId: bodyshop.id,
|
||||||
|
conversationId: selectedConversation
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.emit("leave-bodyshop-conversation", { bodyshopId: bodyshop.id, conversationId: selectedConversation });
|
socket.emit("leave-bodyshop-conversation", {
|
||||||
|
bodyshopId: bodyshop.id,
|
||||||
|
conversationId: selectedConversation
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}, [selectedConversation, bodyshop, socket]);
|
}, [selectedConversation, bodyshop, socket]);
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { QUERY_ALL_ASSOCIATIONS, UPDATE_ACTIVE_ASSOCIATION } from "../../graphql
|
|||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import ProfileShopsComponent from "./profile-shops.component";
|
import ProfileShopsComponent from "./profile-shops.component";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { getToken } from "firebase/messaging";
|
import { getToken } from " firebase/messaging";
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ const useSocket = (bodyshop) => {
|
|||||||
store.dispatch(setWssStatus("disconnected"));
|
store.dispatch(setWssStatus("disconnected"));
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO: Check these handlers.
|
|
||||||
socketInstance.on("connect", handleConnect);
|
socketInstance.on("connect", handleConnect);
|
||||||
socketInstance.on("reconnect", handleReconnect);
|
socketInstance.on("reconnect", handleReconnect);
|
||||||
socketInstance.on("connect_error", handleConnectionError);
|
socketInstance.on("connect_error", handleConnectionError);
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
export default async function FcmHandler({ client, payload }) {
|
|
||||||
console.log("FCM", payload);
|
|
||||||
// switch (payload.type) {
|
|
||||||
// case "messaging-inbound":
|
|
||||||
// client.cache.modify({
|
|
||||||
// id: client.cache.identify({
|
|
||||||
// __typename: "conversations",
|
|
||||||
// id: payload.conversationid
|
|
||||||
// }),
|
|
||||||
// fields: {
|
|
||||||
// messages_aggregate(cached) {
|
|
||||||
// return { aggregate: { count: cached.aggregate.count + 1 } };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// client.cache.modify({
|
|
||||||
// fields: {
|
|
||||||
// messages_aggregate(cached) {
|
|
||||||
// return { aggregate: { count: cached.aggregate.count + 1 } };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// break;
|
|
||||||
// case "messaging-outbound":
|
|
||||||
// client.cache.modify({
|
|
||||||
// id: client.cache.identify({
|
|
||||||
// __typename: "conversations",
|
|
||||||
// id: payload.conversationid
|
|
||||||
// }),
|
|
||||||
// fields: {
|
|
||||||
// updated_at(oldupdated0) {
|
|
||||||
// return new Date();
|
|
||||||
// }
|
|
||||||
// // messages_aggregate(cached) {
|
|
||||||
// // return { aggregate: { count: cached.aggregate.count + 1 } };
|
|
||||||
// // },
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// break;
|
|
||||||
// case "messaging-mark-conversation-read":
|
|
||||||
// let previousUnreadCount = 0;
|
|
||||||
// client.cache.modify({
|
|
||||||
// id: client.cache.identify({
|
|
||||||
// __typename: "conversations",
|
|
||||||
// id: payload.conversationid
|
|
||||||
// }),
|
|
||||||
// fields: {
|
|
||||||
// messages_aggregate(cached) {
|
|
||||||
// previousUnreadCount = cached.aggregate.count;
|
|
||||||
// return { aggregate: { count: 0 } };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// client.cache.modify({
|
|
||||||
// fields: {
|
|
||||||
// messages_aggregate(cached) {
|
|
||||||
// return {
|
|
||||||
// aggregate: {
|
|
||||||
// count: cached.aggregate.count - previousUnreadCount
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// console.log("No payload type set.");
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,6 @@ const logger = require("../utils/logger");
|
|||||||
const InstanceManager = require("../utils/instanceMgr").default;
|
const InstanceManager = require("../utils/instanceMgr").default;
|
||||||
|
|
||||||
exports.receive = async (req, res) => {
|
exports.receive = async (req, res) => {
|
||||||
// Perform request validation
|
|
||||||
const {
|
const {
|
||||||
ioRedis,
|
ioRedis,
|
||||||
ioHelpers: { getBodyshopRoom, getBodyshopConversationRoom }
|
ioHelpers: { getBodyshopRoom, getBodyshopConversationRoom }
|
||||||
@@ -50,20 +49,17 @@ exports.receive = async (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (response.bodyshops[0]) {
|
if (response.bodyshops[0]) {
|
||||||
if (response.bodyshops[0].conversations.length === 0) {
|
const bodyshop = response.bodyshops[0];
|
||||||
// No conversation found, create one
|
if (bodyshop.conversations.length === 0) {
|
||||||
newMessage.conversation = {
|
newMessage.conversation = {
|
||||||
data: {
|
data: {
|
||||||
bodyshopid: response.bodyshops[0].id,
|
bodyshopid: bodyshop.id,
|
||||||
phone_num: phone(req.body.From).phoneNumber
|
phone_num: phone(req.body.From).phoneNumber
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Insert new conversation and message
|
|
||||||
const insertresp = await client.request(queries.RECEIVE_MESSAGE, { msg: newMessage });
|
const insertresp = await client.request(queries.RECEIVE_MESSAGE, { msg: newMessage });
|
||||||
|
|
||||||
// Safely access conversation and message
|
|
||||||
const createdConversation = insertresp?.insert_messages?.returning?.[0]?.conversation || null;
|
const createdConversation = insertresp?.insert_messages?.returning?.[0]?.conversation || null;
|
||||||
const message = insertresp?.insert_messages?.returning?.[0];
|
const message = insertresp?.insert_messages?.returning?.[0];
|
||||||
|
|
||||||
@@ -71,12 +67,12 @@ exports.receive = async (req, res) => {
|
|||||||
throw new Error("Conversation data is missing from the response.");
|
throw new Error("Conversation data is missing from the response.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const broadcastRoom = getBodyshopRoom(r2.insert_messages.returning[0].conversation.bodyshop.id);
|
const broadcastRoom = getBodyshopRoom(createdConversation.bodyshop.id);
|
||||||
const conversationRoom = getBodyshopConversationRoom({
|
const conversationRoom = getBodyshopConversationRoom({
|
||||||
bodyshopId: message.conversation.bodyshop.id,
|
bodyshopId: message.conversation.bodyshop.id,
|
||||||
conversationId: message.conversation.id
|
conversationId: message.conversation.id
|
||||||
});
|
});
|
||||||
// Broadcast new message to the conversation room
|
|
||||||
ioRedis.to(broadcastRoom).emit("new-message-summary", {
|
ioRedis.to(broadcastRoom).emit("new-message-summary", {
|
||||||
isoutbound: false,
|
isoutbound: false,
|
||||||
existingConversation: false,
|
existingConversation: false,
|
||||||
@@ -86,6 +82,7 @@ exports.receive = async (req, res) => {
|
|||||||
msid: message.sid,
|
msid: message.sid,
|
||||||
summary: true
|
summary: true
|
||||||
});
|
});
|
||||||
|
|
||||||
ioRedis.to(conversationRoom).emit("new-message-detailed", {
|
ioRedis.to(conversationRoom).emit("new-message-detailed", {
|
||||||
newMessage: message,
|
newMessage: message,
|
||||||
isoutbound: false,
|
isoutbound: false,
|
||||||
@@ -103,24 +100,12 @@ exports.receive = async (req, res) => {
|
|||||||
res.status(200).send("");
|
res.status(200).send("");
|
||||||
return;
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.log("sms-inbound-error", "ERROR", "api", null, {
|
handleError(req, e, res, "RECEIVE_MESSAGE");
|
||||||
msid: req.body.SmsMessageSid,
|
|
||||||
text: req.body.Body,
|
|
||||||
image: !!req.body.MediaUrl0,
|
|
||||||
image_path: generateMediaArray(req.body),
|
|
||||||
messagingServiceSid: req.body.MessagingServiceSid,
|
|
||||||
error: e
|
|
||||||
});
|
|
||||||
|
|
||||||
res.status(500).json(e);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (response.bodyshops[0].conversations.length === 1) {
|
} else if (bodyshop.conversations.length === 1) {
|
||||||
// Add to the existing conversation
|
newMessage.conversationid = bodyshop.conversations[0].id;
|
||||||
// conversation UPDATED
|
|
||||||
newMessage.conversationid = response.bodyshops[0].conversations[0].id;
|
|
||||||
} else {
|
} else {
|
||||||
// Duplicate phone error
|
|
||||||
logger.log("sms-inbound-error", "ERROR", "api", null, {
|
logger.log("sms-inbound-error", "ERROR", "api", null, {
|
||||||
msid: req.body.SmsMessageSid,
|
msid: req.body.SmsMessageSid,
|
||||||
text: req.body.Body,
|
text: req.body.Body,
|
||||||
@@ -134,7 +119,6 @@ exports.receive = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Insert message into an existing conversation
|
|
||||||
const insertresp = await client.request(queries.INSERT_MESSAGE, {
|
const insertresp = await client.request(queries.INSERT_MESSAGE, {
|
||||||
msg: newMessage,
|
msg: newMessage,
|
||||||
conversationid: newMessage.conversationid
|
conversationid: newMessage.conversationid
|
||||||
@@ -167,52 +151,36 @@ exports.receive = async (req, res) => {
|
|||||||
fcmresp
|
fcmresp
|
||||||
});
|
});
|
||||||
|
|
||||||
const broadcastRoom = getBodyshopRoom(r2.insert_messages.returning[0].conversation.bodyshop.id);
|
const broadcastRoom = getBodyshopRoom(message.conversation.bodyshop.id);
|
||||||
const conversationRoom = getBodyshopConversationRoom({
|
const conversationRoom = getBodyshopConversationRoom({
|
||||||
bodyshopId: message.conversation.bodyshop.id,
|
bodyshopId: message.conversation.bodyshop.id,
|
||||||
conversationId: message.conversation.id
|
conversationId: message.conversation.id
|
||||||
});
|
});
|
||||||
// Broadcast new message to the conversation room
|
|
||||||
ioRedis.to(broadcastRoom).emit("new-message-summary", {
|
ioRedis.to(broadcastRoom).emit("new-message-summary", {
|
||||||
isoutbound: false,
|
isoutbound: false,
|
||||||
existingConversation: true,
|
existingConversation: true,
|
||||||
conversationId: conversationid,
|
conversationId: message.conversationid,
|
||||||
updated_at: message.updated_at,
|
updated_at: message.updated_at,
|
||||||
msid: message.sid,
|
msid: message.sid,
|
||||||
summary: true
|
summary: true
|
||||||
});
|
});
|
||||||
|
|
||||||
ioRedis.to(conversationRoom).emit("new-message-detailed", {
|
ioRedis.to(conversationRoom).emit("new-message-detailed", {
|
||||||
newMessage: message,
|
newMessage: message,
|
||||||
isoutbound: false,
|
isoutbound: false,
|
||||||
existingConversation: true,
|
existingConversation: true,
|
||||||
conversationId: conversationid,
|
conversationId: message.conversationid,
|
||||||
summary: false
|
summary: false
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(200).send("");
|
res.status(200).send("");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.log("sms-inbound-error", "ERROR", "api", null, {
|
handleError(req, e, res, "INSERT_MESSAGE");
|
||||||
msid: req.body.SmsMessageSid,
|
|
||||||
text: req.body.Body,
|
|
||||||
image: !!req.body.MediaUrl0,
|
|
||||||
image_path: generateMediaArray(req.body),
|
|
||||||
messagingServiceSid: req.body.MessagingServiceSid,
|
|
||||||
error: e
|
|
||||||
});
|
|
||||||
|
|
||||||
res.status(500).json(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.log("sms-inbound-error", "ERROR", "api", null, {
|
handleError(req, e, res, "FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID");
|
||||||
msid: req.body.SmsMessageSid,
|
|
||||||
text: req.body.Body,
|
|
||||||
image: !!req.body.MediaUrl0,
|
|
||||||
image_path: generateMediaArray(req.body),
|
|
||||||
messagingServiceSid: req.body.MessagingServiceSid,
|
|
||||||
error: e
|
|
||||||
});
|
|
||||||
res.status(500).json(e);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -228,3 +196,17 @@ const generateMediaArray = (body) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleError = (req, error, res, context) => {
|
||||||
|
logger.log("sms-inbound-error", "ERROR", "api", null, {
|
||||||
|
msid: req.body.SmsMessageSid,
|
||||||
|
text: req.body.Body,
|
||||||
|
image: !!req.body.MediaUrl0,
|
||||||
|
image_path: generateMediaArray(req.body),
|
||||||
|
messagingServiceSid: req.body.MessagingServiceSid,
|
||||||
|
context,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(500).json({ error: error.message || "Internal Server Error" });
|
||||||
|
};
|
||||||
|
|||||||
@@ -8,10 +8,9 @@ const { phone } = require("phone");
|
|||||||
const queries = require("../graphql-client/queries");
|
const queries = require("../graphql-client/queries");
|
||||||
const logger = require("../utils/logger");
|
const logger = require("../utils/logger");
|
||||||
const client = twilio(process.env.TWILIO_AUTH_TOKEN, process.env.TWILIO_AUTH_KEY);
|
const client = twilio(process.env.TWILIO_AUTH_TOKEN, process.env.TWILIO_AUTH_KEY);
|
||||||
const { admin } = require("../firebase/firebase-handler");
|
|
||||||
const gqlClient = require("../graphql-client/graphql-client").client;
|
const gqlClient = require("../graphql-client/graphql-client").client;
|
||||||
|
|
||||||
exports.send = (req, res) => {
|
exports.send = async (req, res) => {
|
||||||
const { to, messagingServiceSid, body, conversationid, selectedMedia, imexshopid } = req.body;
|
const { to, messagingServiceSid, body, conversationid, selectedMedia, imexshopid } = req.body;
|
||||||
const {
|
const {
|
||||||
ioRedis,
|
ioRedis,
|
||||||
@@ -19,7 +18,7 @@ exports.send = (req, res) => {
|
|||||||
} = req;
|
} = req;
|
||||||
|
|
||||||
logger.log("sms-outbound", "DEBUG", req.user.email, null, {
|
logger.log("sms-outbound", "DEBUG", req.user.email, null, {
|
||||||
messagingServiceSid: messagingServiceSid,
|
messagingServiceSid,
|
||||||
to: phone(to).phoneNumber,
|
to: phone(to).phoneNumber,
|
||||||
mediaUrl: selectedMedia.map((i) => i.src),
|
mediaUrl: selectedMedia.map((i) => i.src),
|
||||||
text: body,
|
text: body,
|
||||||
@@ -30,85 +29,10 @@ exports.send = (req, res) => {
|
|||||||
image_path: req.body.selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
|
image_path: req.body.selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!to && !!messagingServiceSid && (!!body || !!selectedMedia.length > 0) && !!conversationid) {
|
if (!to || !messagingServiceSid || (!body && selectedMedia.length === 0) || !conversationid) {
|
||||||
client.messages
|
|
||||||
.create({
|
|
||||||
body: body,
|
|
||||||
messagingServiceSid: messagingServiceSid,
|
|
||||||
to: phone(to).phoneNumber,
|
|
||||||
mediaUrl: selectedMedia.map((i) => i.src)
|
|
||||||
})
|
|
||||||
.then((message) => {
|
|
||||||
let newMessage = {
|
|
||||||
msid: message.sid,
|
|
||||||
text: body,
|
|
||||||
conversationid,
|
|
||||||
isoutbound: true,
|
|
||||||
userid: req.user.email,
|
|
||||||
image: req.body.selectedMedia.length > 0,
|
|
||||||
image_path: req.body.selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
|
|
||||||
};
|
|
||||||
gqlClient
|
|
||||||
.request(queries.INSERT_MESSAGE, { msg: newMessage, conversationid })
|
|
||||||
.then((r2) => {
|
|
||||||
//console.log("Responding GQL Message ID", JSON.stringify(r2));
|
|
||||||
logger.log("sms-outbound-success", "DEBUG", req.user.email, null, {
|
|
||||||
msid: message.sid,
|
|
||||||
conversationid
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
type: "messaging-outbound",
|
|
||||||
conversationid: newMessage.conversationid || ""
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO Verify
|
|
||||||
// const messageData = response.insert_messages.returning[0];
|
|
||||||
|
|
||||||
// Broadcast new message to conversation room
|
|
||||||
const broadcastRoom = getBodyshopRoom(r2.insert_messages.returning[0].conversation.bodyshop.id);
|
|
||||||
const conversationRoom = getBodyshopConversationRoom({
|
|
||||||
bodyshopId: r2.insert_messages.returning[0].conversation.bodyshop.id,
|
|
||||||
conversationId: r2.insert_messages.returning[0].conversation.id
|
|
||||||
});
|
|
||||||
|
|
||||||
ioRedis.to(broadcastRoom).emit("new-message-summary", {
|
|
||||||
isoutbound: true,
|
|
||||||
conversationId: conversationid,
|
|
||||||
updated_at: r2.insert_messages.returning[0].updated_at,
|
|
||||||
msid: message.sid,
|
|
||||||
summary: true
|
|
||||||
});
|
|
||||||
ioRedis.to(conversationRoom).emit("new-message-detailed", {
|
|
||||||
newMessage: r2.insert_messages.returning[0],
|
|
||||||
conversationId: conversationid,
|
|
||||||
summary: false
|
|
||||||
});
|
|
||||||
res.sendStatus(200);
|
|
||||||
})
|
|
||||||
.catch((e2) => {
|
|
||||||
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
|
|
||||||
msid: message.sid,
|
|
||||||
conversationid,
|
|
||||||
error: e2.message,
|
|
||||||
stack: e2.stack
|
|
||||||
});
|
|
||||||
|
|
||||||
//res.json({ success: false, message: e2 });
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((e1) => {
|
|
||||||
//res.json({ success: false, message: error });
|
|
||||||
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
|
|
||||||
conversationid,
|
|
||||||
error: e1.message,
|
|
||||||
stack: e1.stack
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
|
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
|
||||||
type: "missing-parameters",
|
type: "missing-parameters",
|
||||||
messagingServiceSid: messagingServiceSid,
|
messagingServiceSid,
|
||||||
to: phone(to).phoneNumber,
|
to: phone(to).phoneNumber,
|
||||||
text: body,
|
text: body,
|
||||||
conversationid,
|
conversationid,
|
||||||
@@ -118,5 +42,72 @@ exports.send = (req, res) => {
|
|||||||
image_path: req.body.selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
|
image_path: req.body.selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
|
||||||
});
|
});
|
||||||
res.status(400).json({ success: false, message: "Missing required parameter(s)." });
|
res.status(400).json({ success: false, message: "Missing required parameter(s)." });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const message = await client.messages.create({
|
||||||
|
body,
|
||||||
|
messagingServiceSid,
|
||||||
|
to: phone(to).phoneNumber,
|
||||||
|
mediaUrl: selectedMedia.map((i) => i.src)
|
||||||
|
});
|
||||||
|
|
||||||
|
const newMessage = {
|
||||||
|
msid: message.sid,
|
||||||
|
text: body,
|
||||||
|
conversationid,
|
||||||
|
isoutbound: true,
|
||||||
|
userid: req.user.email,
|
||||||
|
image: req.body.selectedMedia.length > 0,
|
||||||
|
image_path: req.body.selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const gqlResponse = await gqlClient.request(queries.INSERT_MESSAGE, { msg: newMessage, conversationid });
|
||||||
|
|
||||||
|
logger.log("sms-outbound-success", "DEBUG", req.user.email, null, {
|
||||||
|
msid: message.sid,
|
||||||
|
conversationid
|
||||||
|
});
|
||||||
|
|
||||||
|
const insertedMessage = gqlResponse.insert_messages.returning[0];
|
||||||
|
const broadcastRoom = getBodyshopRoom(insertedMessage.conversation.bodyshop.id);
|
||||||
|
const conversationRoom = getBodyshopConversationRoom({
|
||||||
|
bodyshopId: insertedMessage.conversation.bodyshop.id,
|
||||||
|
conversationId: insertedMessage.conversation.id
|
||||||
|
});
|
||||||
|
|
||||||
|
ioRedis.to(broadcastRoom).emit("new-message-summary", {
|
||||||
|
isoutbound: true,
|
||||||
|
conversationId: conversationid,
|
||||||
|
updated_at: insertedMessage.updated_at,
|
||||||
|
msid: message.sid,
|
||||||
|
summary: true
|
||||||
|
});
|
||||||
|
|
||||||
|
ioRedis.to(conversationRoom).emit("new-message-detailed", {
|
||||||
|
newMessage: insertedMessage,
|
||||||
|
conversationId: conversationid,
|
||||||
|
summary: false
|
||||||
|
});
|
||||||
|
|
||||||
|
res.sendStatus(200);
|
||||||
|
} catch (gqlError) {
|
||||||
|
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
|
||||||
|
msid: message.sid,
|
||||||
|
conversationid,
|
||||||
|
error: gqlError.message,
|
||||||
|
stack: gqlError.stack
|
||||||
|
});
|
||||||
|
res.status(500).json({ success: false, message: "Failed to insert message into database." });
|
||||||
|
}
|
||||||
|
} catch (twilioError) {
|
||||||
|
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
|
||||||
|
conversationid,
|
||||||
|
error: twilioError.message,
|
||||||
|
stack: twilioError.stack
|
||||||
|
});
|
||||||
|
res.status(500).json({ success: false, message: "Failed to send message through Twilio." });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
const { admin } = require("../firebase/firebase-handler");
|
const { admin } = require("../firebase/firebase-handler");
|
||||||
const { MARK_MESSAGES_AS_READ, GET_CONVERSATIONS, GET_CONVERSATION_DETAILS } = require("../graphql-client/queries");
|
|
||||||
const { phone } = require("phone");
|
|
||||||
const { client: gqlClient } = require("../graphql-client/graphql-client");
|
|
||||||
const queries = require("../graphql-client/queries");
|
|
||||||
const twilio = require("twilio");
|
|
||||||
const client = require("../graphql-client/graphql-client").client;
|
|
||||||
|
|
||||||
const twilioClient = twilio(process.env.TWILIO_AUTH_TOKEN, process.env.TWILIO_AUTH_KEY);
|
|
||||||
|
|
||||||
const redisSocketEvents = ({
|
const redisSocketEvents = ({
|
||||||
io,
|
io,
|
||||||
@@ -84,6 +76,7 @@ const redisSocketEvents = ({
|
|||||||
};
|
};
|
||||||
socket.on("update-token", updateToken);
|
socket.on("update-token", updateToken);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Room Broadcast Events
|
// Room Broadcast Events
|
||||||
const registerRoomAndBroadcastEvents = (socket) => {
|
const registerRoomAndBroadcastEvents = (socket) => {
|
||||||
const joinBodyshopRoom = (bodyshopUUID) => {
|
const joinBodyshopRoom = (bodyshopUUID) => {
|
||||||
@@ -138,6 +131,7 @@ const redisSocketEvents = ({
|
|||||||
|
|
||||||
socket.on("disconnect", disconnect);
|
socket.on("disconnect", disconnect);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Messaging Events
|
// Messaging Events
|
||||||
const registerMessagingEvents = (socket) => {
|
const registerMessagingEvents = (socket) => {
|
||||||
const joinConversationRoom = async ({ bodyshopId, conversationId }) => {
|
const joinConversationRoom = async ({ bodyshopId, conversationId }) => {
|
||||||
@@ -145,19 +139,26 @@ const redisSocketEvents = ({
|
|||||||
const room = getBodyshopConversationRoom({ bodyshopId, conversationId });
|
const room = getBodyshopConversationRoom({ bodyshopId, conversationId });
|
||||||
socket.join(room);
|
socket.join(room);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("error", "Failed to join conversation", error);
|
logger.log("Failed to Join Conversation Room", "error", "io-redis", null, {
|
||||||
|
bodyshopId,
|
||||||
|
conversationId,
|
||||||
|
error: error.message,
|
||||||
|
stack: error.stack
|
||||||
|
});
|
||||||
socket.emit("error", { message: "Failed to join conversation" });
|
socket.emit("error", { message: "Failed to join conversation" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const leaveConversationRoom = ({ bodyshopId, conversationId }) => {
|
const leaveConversationRoom = ({ bodyshopId, conversationId }) => {
|
||||||
try {
|
try {
|
||||||
const room = getBodyshopConversationRoom({ bodyshopId, conversationId });
|
const room = getBodyshopConversationRoom({ bodyshopId, conversationId });
|
||||||
socket.leave(room);
|
socket.leave(room);
|
||||||
// Optionally notify the client
|
|
||||||
//socket.emit("conversation-left", { conversationId });
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
socket.emit("error", { message: "Failed to leave conversation" });
|
logger.log("Failed to Leave Conversation Room", "error", "io-redis", null, {
|
||||||
|
bodyshopId,
|
||||||
|
conversationId,
|
||||||
|
error: error.message,
|
||||||
|
stack: error.stack
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user