Notif
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
|||||||
} from "./data.js";
|
} from "./data.js";
|
||||||
import { renderChat } from "./render.js";
|
import { renderChat } from "./render.js";
|
||||||
import { initWebSocket } from "./wsModule.js";
|
import { initWebSocket } from "./wsModule.js";
|
||||||
|
import { primeNotifications } from "./notifications.js";
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
const chat = document.getElementById("chat");
|
const chat = document.getElementById("chat");
|
||||||
@@ -25,6 +26,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
|
|
||||||
chat.style.display = "";
|
chat.style.display = "";
|
||||||
inputContainer.style.display = "flex";
|
inputContainer.style.display = "flex";
|
||||||
|
primeNotifications();
|
||||||
|
|
||||||
const defaultName = "Anon";
|
const defaultName = "Anon";
|
||||||
const MAX_NAME_LEN = 15; // server limit is NAME_MAX_LENGTH-1 (15 chars)
|
const MAX_NAME_LEN = 15; // server limit is NAME_MAX_LENGTH-1 (15 chars)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// coms/client/public/data.js
|
// coms/client/public/data.js
|
||||||
// Data module: holds the in‐memory threads, notices and reply state
|
// Data module: holds the in‐memory threads, notices and reply state
|
||||||
|
|
||||||
|
import { notifyNotice } from "./notifications.js";
|
||||||
|
|
||||||
// Map of all messages and notices by ID (string IDs)
|
// Map of all messages and notices by ID (string IDs)
|
||||||
// Client’s own session ID
|
// Client’s own session ID
|
||||||
let myId = null;
|
let myId = null;
|
||||||
@@ -139,6 +141,7 @@ function addNotice(content) {
|
|||||||
children: [],
|
children: [],
|
||||||
});
|
});
|
||||||
rootIds.push(id);
|
rootIds.push(id);
|
||||||
|
notifyNotice(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
59
client/public/notifications.js
Normal file
59
client/public/notifications.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Simple notification helpers for the chat client.
|
||||||
|
|
||||||
|
const APP_NAME = "COMS";
|
||||||
|
|
||||||
|
function supportsNotifications() {
|
||||||
|
return typeof Notification !== "undefined";
|
||||||
|
}
|
||||||
|
|
||||||
|
function stripHtml(input) {
|
||||||
|
const div = document.createElement("div");
|
||||||
|
div.innerHTML = input;
|
||||||
|
return div.textContent || div.innerText || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask for permission if not already granted/denied.
|
||||||
|
*/
|
||||||
|
function primeNotifications() {
|
||||||
|
if (!supportsNotifications()) return;
|
||||||
|
if (Notification.permission === "default") {
|
||||||
|
Notification.requestPermission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showNotification(title, body) {
|
||||||
|
if (!supportsNotifications()) return;
|
||||||
|
const options = { body };
|
||||||
|
if (Notification.permission === "granted") {
|
||||||
|
new Notification(title, options);
|
||||||
|
} else if (Notification.permission === "default") {
|
||||||
|
Notification.requestPermission().then((perm) => {
|
||||||
|
if (perm === "granted") new Notification(title, options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the user of a system notice.
|
||||||
|
* @param {string} content - HTML or text content of the notice.
|
||||||
|
*/
|
||||||
|
function notifyNotice(content) {
|
||||||
|
const text = stripHtml(content);
|
||||||
|
if (!text) return;
|
||||||
|
showNotification(`${APP_NAME} notice`, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the user that someone replied directly to their thread.
|
||||||
|
* @param {string} authorName
|
||||||
|
* @param {string} content
|
||||||
|
*/
|
||||||
|
function notifyDirectReply(authorName, content) {
|
||||||
|
const text = stripHtml(content);
|
||||||
|
if (!text) return;
|
||||||
|
const name = authorName || "Anon";
|
||||||
|
showNotification(`${name} replied to your thread`, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { primeNotifications, notifyNotice, notifyDirectReply };
|
||||||
@@ -13,12 +13,15 @@ import {
|
|||||||
updateUser,
|
updateUser,
|
||||||
getGroupedUsers,
|
getGroupedUsers,
|
||||||
setMyId,
|
setMyId,
|
||||||
|
getMyId,
|
||||||
|
getThreads,
|
||||||
clearData,
|
clearData,
|
||||||
users,
|
users,
|
||||||
setFocused,
|
setFocused,
|
||||||
setReplyTo,
|
setReplyTo,
|
||||||
} from "./data.js";
|
} from "./data.js";
|
||||||
import { renderChat } from "./render.js";
|
import { renderChat } from "./render.js";
|
||||||
|
import { notifyDirectReply } from "./notifications.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize WebSocket connection and wire up event handlers.
|
* Initialize WebSocket connection and wire up event handlers.
|
||||||
@@ -132,6 +135,23 @@ export function initWebSocket(
|
|||||||
? null
|
? null
|
||||||
: String(parent),
|
: String(parent),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Notify when someone else replies directly to one of my root messages.
|
||||||
|
const myId = getMyId();
|
||||||
|
const parentId =
|
||||||
|
parent === null || parent === undefined || parent === "-1"
|
||||||
|
? null
|
||||||
|
: String(parent);
|
||||||
|
if (myId && parentId && author?.id && String(author.id) !== myId) {
|
||||||
|
const parentMsg = getThreads().get(parentId);
|
||||||
|
if (
|
||||||
|
parentMsg &&
|
||||||
|
parentMsg.parent === null &&
|
||||||
|
parentMsg.authorId === myId
|
||||||
|
) {
|
||||||
|
notifyDirectReply(username, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "msg_ack": {
|
case "msg_ack": {
|
||||||
|
|||||||
Reference in New Issue
Block a user