Tighten admin visitor facts and add widget branding

This commit is contained in:
rajchales-monito
2026-07-23 22:45:28 +02:00
parent 8c71dbf1bf
commit b56469e774
4 changed files with 56 additions and 19 deletions
+20 -3
View File
@@ -259,7 +259,7 @@ function adminConversations(res) {
(SELECT body FROM messages WHERE conversation_id = c.id ORDER BY id DESC LIMIT 1) AS last_body,
(SELECT COUNT(*) FROM messages WHERE conversation_id = c.id) AS message_count,
(SELECT COUNT(*) FROM attachments WHERE conversation_id = c.id AND mime_type LIKE 'image/%') AS image_count,
(SELECT public_url FROM attachments WHERE conversation_id = c.id AND mime_type LIKE 'image/%' ORDER BY id DESC LIMIT 1) AS first_image_url
(SELECT COUNT(*) FROM conversations vc WHERE vc.site_id = c.site_id AND vc.visitor_token = c.visitor_token) AS visitor_conversation_count
FROM conversations c
JOIN sites s ON s.id = c.site_id
ORDER BY datetime(c.last_message_at) DESC, c.id DESC
@@ -523,7 +523,9 @@ function formatConversationSummary(row) {
lastBody: row.last_body,
messageCount: row.message_count,
imageCount: row.image_count || 0,
firstImageUrl: row.first_image_url,
pageCount: pageCount(row.browsing_history_json),
sessionSeconds: sessionSeconds(row.browsing_history_json, row.created_at),
visitorConversationCount: row.visitor_conversation_count || 1,
lastMessageAt: row.last_message_at,
createdAt: row.created_at
};
@@ -567,7 +569,8 @@ function getDefaultSite() {
function findConversation(publicId) {
return db.prepare(`
SELECT c.*, s.site_key
SELECT c.*, s.site_key,
(SELECT COUNT(*) FROM conversations vc WHERE vc.site_id = c.site_id AND vc.visitor_token = c.visitor_token) AS visitor_conversation_count
FROM conversations c
JOIN sites s ON s.id = c.site_id
WHERE c.public_id = ?
@@ -665,6 +668,20 @@ function parseJson(value, fallback) {
}
}
function pageCount(historyJson) {
return new Set(parseJson(historyJson, []).map((item) => item.url).filter(Boolean)).size;
}
function sessionSeconds(historyJson, createdAt) {
const history = parseJson(historyJson, []);
const times = history
.map((item) => Date.parse(item.at))
.filter((value) => Number.isFinite(value));
if (times.length > 1) return Math.max(0, Math.round((Math.max(...times) - Math.min(...times)) / 1000));
const created = Date.parse(`${createdAt}Z`);
return Number.isFinite(created) ? Math.max(0, Math.round((Date.now() - created) / 1000)) : 0;
}
function id(prefix) {
return `${prefix}_${crypto.randomBytes(12).toString("hex")}`;
}