@@ -123,7 +123,7 @@ mutation RECEIVE_MESSAGE($msg: [messages_insert_input!]!) {
|
||||
|
||||
exports.INSERT_MESSAGE = `
|
||||
mutation INSERT_MESSAGE($msg: [messages_insert_input!]!, $conversationid: uuid!) {
|
||||
update_conversations_by_pk(pk_columns: {id: $conversationid}, _set: {archived: false}) {
|
||||
update_conversations_by_pk(pk_columns: { id: $conversationid }, _set: { archived: false }) {
|
||||
id
|
||||
archived
|
||||
}
|
||||
@@ -147,6 +147,7 @@ mutation INSERT_MESSAGE($msg: [messages_insert_input!]!, $conversationid: uuid!)
|
||||
image_path
|
||||
image
|
||||
isoutbound
|
||||
is_system
|
||||
msid
|
||||
read
|
||||
text
|
||||
|
||||
@@ -3,7 +3,7 @@ const router = express.Router();
|
||||
const twilio = require("twilio");
|
||||
const { receive } = require("../sms/receive");
|
||||
const { send } = require("../sms/send");
|
||||
const { status, markConversationRead } = require("../sms/status");
|
||||
const { status, markConversationRead, markLastMessageUnread } = require("../sms/status");
|
||||
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
|
||||
|
||||
// Twilio Webhook Middleware for production
|
||||
@@ -14,5 +14,6 @@ router.post("/receive", twilioWebhookMiddleware, receive);
|
||||
router.post("/send", validateFirebaseIdTokenMiddleware, send);
|
||||
router.post("/status", twilioWebhookMiddleware, status);
|
||||
router.post("/markConversationRead", validateFirebaseIdTokenMiddleware, markConversationRead);
|
||||
router.post("/markLastMessageUnread", validateFirebaseIdTokenMiddleware, markLastMessageUnread);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -61,7 +61,8 @@ const send = async (req, res) => {
|
||||
isoutbound: true,
|
||||
userid: req.user.email,
|
||||
image: selectedMedia.length > 0,
|
||||
image_path: selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
|
||||
image_path: selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : [],
|
||||
is_system: false
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
@@ -8,6 +8,46 @@ const {
|
||||
const logger = require("../utils/logger");
|
||||
const { phone } = require("phone");
|
||||
|
||||
// Local GraphQL for “mark unread” (kept here to avoid requiring edits to graphql-client/queries.js)
|
||||
const GET_LAST_INBOUND_NON_SYSTEM_MESSAGE = `
|
||||
query GetLastInboundNonSystemMessage($conversationId: uuid!) {
|
||||
messages(
|
||||
where: {
|
||||
conversationid: { _eq: $conversationId }
|
||||
isoutbound: { _eq: false }
|
||||
is_system: { _eq: false }
|
||||
}
|
||||
order_by: { created_at: desc }
|
||||
limit: 1
|
||||
) {
|
||||
id
|
||||
created_at
|
||||
read
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const MARK_LAST_INBOUND_MESSAGE_UNREAD_MAX_ONE = `
|
||||
mutation MarkLastInboundMessageUnreadMaxOne($conversationId: uuid!, $lastId: uuid!) {
|
||||
markOthersRead: update_messages(
|
||||
_set: { read: true }
|
||||
where: {
|
||||
conversationid: { _eq: $conversationId }
|
||||
isoutbound: { _eq: false }
|
||||
is_system: { _eq: false }
|
||||
id: { _neq: $lastId }
|
||||
}
|
||||
) {
|
||||
affected_rows
|
||||
returning { id }
|
||||
}
|
||||
|
||||
markLastUnread: update_messages_by_pk(pk_columns: { id: $lastId }, _set: { read: false }) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Handle the status of an SMS message
|
||||
* @param req
|
||||
@@ -176,7 +216,80 @@ const markConversationRead = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark last inbound (customer) non-system message as unread.
|
||||
* Enforces: max unread inbound non-system messages per thread = 1
|
||||
*
|
||||
* Body: { conversationId, imexshopid, bodyshopid }
|
||||
*/
|
||||
const markLastMessageUnread = async (req, res) => {
|
||||
const {
|
||||
ioRedis,
|
||||
ioHelpers: { getBodyshopRoom }
|
||||
} = req;
|
||||
|
||||
const { conversationId, imexshopid, bodyshopid } = req.body;
|
||||
|
||||
if (!conversationId || !imexshopid || !bodyshopid) {
|
||||
return res.status(400).json({ error: "Invalid conversation data provided." });
|
||||
}
|
||||
|
||||
try {
|
||||
const lastResp = await client.request(GET_LAST_INBOUND_NON_SYSTEM_MESSAGE, { conversationId });
|
||||
const last = lastResp?.messages?.[0];
|
||||
|
||||
if (!last?.id) {
|
||||
// No inbound message to mark unread
|
||||
const broadcastRoom = getBodyshopRoom(bodyshopid);
|
||||
ioRedis.to(broadcastRoom).emit("conversation-changed", {
|
||||
type: "conversation-marked-unread",
|
||||
conversationId,
|
||||
lastUnreadMessageId: null,
|
||||
messageIdsMarkedRead: [],
|
||||
unreadCount: 0
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
conversationId,
|
||||
lastUnreadMessageId: null,
|
||||
messageIdsMarkedRead: [],
|
||||
unreadCount: 0
|
||||
});
|
||||
}
|
||||
|
||||
const mutResp = await client.request(MARK_LAST_INBOUND_MESSAGE_UNREAD_MAX_ONE, {
|
||||
conversationId,
|
||||
lastId: last.id
|
||||
});
|
||||
|
||||
const messageIdsMarkedRead = mutResp?.markOthersRead?.returning?.map((m) => m.id) || [];
|
||||
|
||||
const broadcastRoom = getBodyshopRoom(bodyshopid);
|
||||
|
||||
ioRedis.to(broadcastRoom).emit("conversation-changed", {
|
||||
type: "conversation-marked-unread",
|
||||
conversationId,
|
||||
lastUnreadMessageId: last.id,
|
||||
messageIdsMarkedRead,
|
||||
unreadCount: 1
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
conversationId,
|
||||
lastUnreadMessageId: last.id,
|
||||
messageIdsMarkedRead,
|
||||
unreadCount: 1
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error marking last message unread:", error);
|
||||
return res.status(500).json({ error: "Failed to mark last message unread." });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
status,
|
||||
markConversationRead
|
||||
markConversationRead,
|
||||
markLastMessageUnread
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user