diff --git a/js/db.js b/js/db.js
index de62c76..497e74f 100644
--- a/js/db.js
+++ b/js/db.js
@@ -30,6 +30,7 @@ function openDb() {
msgStore = db.createObjectStore("messages", { keyPath: "id" });
msgStore.createIndex("from", "from", { unique: false });
msgStore.createIndex("fingerprint", ["from", "timestamp"], { unique: false });
+ msgStore.createIndex("cidTimestampId", ["chatId", "timestamp", "id"], { unique: false });
} else {
msgStore = tx.objectStore("messages");
}
@@ -172,6 +173,39 @@ export async function loadLatestMessages(chatId, limit = 50) {
});
}
+export async function loadOlderMessages(chatId, oldestTimestamp, oldestId, limit = 50) {
+ const db = await openDb();
+
+ return new Promise((resolve, reject) => {
+ const tx = db.transaction("messages", "readonly");
+ const store = tx.objectStore("messages");
+ const idx = store.index("cidTimestampId");
+
+ const out = [];
+
+ const parsedTimestamp = isNaN(oldestTimestamp) ? oldestTimestamp : Number(oldestTimestamp);
+
+ const range = IDBKeyRange.bound(
+ [chatId, -Infinity, ""],
+ [chatId, parsedTimestamp, oldestId],
+ false,
+ false
+ );
+
+ idx.openCursor(range, "prev").onsuccess = (e) => {
+ const cursor = e.target.result;
+ if (!cursor) return resolve(out);
+
+ out.push(cursor.value);
+
+ if (out.length >= limit) resolve(out);
+ else cursor.continue();
+ };
+
+ tx.onerror = () => reject(tx.error);
+ });
+}
+
export async function upsertMedia(reqId, blob, filename) {
const db = await openDb();
diff --git a/js/storage.js b/js/storage.js
index 1159816..f83d66c 100644
--- a/js/storage.js
+++ b/js/storage.js
@@ -1,4 +1,4 @@
-import { loadChatsSorted, loadLatestMessages, loadMedia, upsertChats, upsertMedia, upsertMessages } from "./db.js";
+import { loadChatsSorted, loadLatestMessages, loadMedia, loadOlderMessages, upsertChats, upsertMedia, upsertMessages } from "./db.js";
import { waha } from "./waha.js";
let online = false;
@@ -107,6 +107,14 @@ export async function getChatMessages(chatId) {
}
}
+export async function getMoreChatMessages(chatId, oldestTimestamp, oldestId, limit = 50) {
+ if (online) {
+ return waha.getChatMessages(chatId, oldestTimestamp);
+ } else {
+ return await loadOlderMessages(chatId, oldestTimestamp, oldestId);
+ }
+}
+
export async function getChatPicture(chatId) {
if (online) {
return await waha.getChatPicture(chatId);
diff --git a/js/ui.js b/js/ui.js
index cfe586d..3642831 100644
--- a/js/ui.js
+++ b/js/ui.js
@@ -1,7 +1,7 @@
import { formatTime } from "./utils.js";
import { waha } from "./waha.js";
import { config } from "./config.js";
-import { getChatPicture, getMessage, getMedia } from "./storage.js";
+import { getChatPicture, getMessage, getMedia, getMoreChatMessages } from "./storage.js";
export const elements = {
chatList: document.getElementById('chat-list'),
@@ -136,19 +136,48 @@ export const ui = {
elements.messagesContainer.innerHTML = '
No messages. Say hello!
';
return;
}
+
+ const loadMore = document.createElement("button");
+ loadMore.classList.add("load-more-btn");
+ loadMore.innerText = "Load more";
+ loadMore.addEventListener('click', () => {
+ this.loadMoreMessages(chatId, userID);
+ });
+ elements.messagesContainer.appendChild(loadMore);
for (const msg of messages) {
- this.appendSingleMessage(msg, activeChatName, userID, chatId);
+ this.appendSingleMessage(msg, userID, chatId);
}
this.scrollToBottom();
},
+
+ async loadMoreMessages(chatId, userId) {
+ const oldest = document.querySelector('.message-group:first-of-type');
+ const oldestTimestamp = oldest.dataset.timestamp;
+ const oldestId = oldest.id;
+ console.log(oldest)
+ console.log(oldestId)
+ console.log(oldestTimestamp)
+
+ const loadMoreButton = document.querySelector('.load-more-btn');
+ loadMoreButton.removeEventListener('click', this.loadMoreMessages);
+
+ const msgs = await getMoreChatMessages(chatId, oldestTimestamp, oldestId);
+ msgs.shift();
+
+ msgs.forEach(async msg => {
+ loadMoreButton.after(this.generateMessage(msg, userId, chatId));
+ });
+
+ loadMoreButton.addEventListener('click', this.loadMoreMessages);
+ },
/**
* Append a single message (used for optimistic updates immediately upon sending)
*/
- appendSingleMessage(msg, activeChatName, userID, chatId, isLocal = false) {
- elements.messagesContainer.appendChild(this.generateMessage(msg, activeChatName, userID, chatId, isLocal))
+ appendSingleMessage(msg, userID, chatId, isLocal = false) {
+ elements.messagesContainer.appendChild(this.generateMessage(msg, userID, chatId, isLocal))
},
generateTempMessageLink(msg) {
@@ -169,7 +198,7 @@ export const ui = {
return a;
},
- generateMessage(msg, activeChatName, userID, chatId, isLocal = false) {
+ generateMessage(msg, userID, chatId, isLocal = false) {
const isOutgoing = msg.fromMe || msg.sender === 'me';
function getPrevMessageElem() {
@@ -181,6 +210,7 @@ export const ui = {
const groupDiv = document.createElement('div');
groupDiv.className = `message-group ${isOutgoing ? 'outgoing' : 'incoming'}`;
groupDiv.id = msg.id;
+ groupDiv.dataset.timestamp = msg.timestamp;
groupDiv.dataset.from = msg.participant || msg.from;
const senderName = isOutgoing ? userID : (msg._data.notifyName || msg.from);
diff --git a/js/waha.js b/js/waha.js
index 3c3050f..66683b1 100644
--- a/js/waha.js
+++ b/js/waha.js
@@ -69,7 +69,7 @@ async function downloadFile(path, options = {}) {
export const waha = {
async getVersion() {
- return request('/api/version');
+ return await request('/api/version');
},
async getChats() {
@@ -89,8 +89,9 @@ export const waha = {
});
},
- async getChatMessages(chatId) {
- return request(`/api/${config.session}/chats/${chatId}/messages?downloadMedia=false&limit=40`);
+ async getChatMessages(chatId, beforeTimestamp) {
+ console.log(`/api/${config.session}/chats/${chatId}/messages?downloadMedia=false&limit=40&sortBy=timestamp${beforeTimestamp ? `&filter.timestamp.gte=${beforeTimestamp}` : "" }`);
+ return request(`/api/${config.session}/chats/${chatId}/messages?downloadMedia=false&limit=40${beforeTimestamp ? `&filter.timestamp.lte=${beforeTimestamp}` : "" }`);
},
async getSingleChatMessage(chatId, messageId, downladMedia) {
diff --git a/style.css b/style.css
index bea420c..3ea409c 100644
--- a/style.css
+++ b/style.css
@@ -506,6 +506,18 @@ input:focus {
radial-gradient(circle at 90% 80%, rgba(168, 85, 247, 0.03) 0%, transparent 40%);
}
+.load-more-btn {
+ margin: auto;
+ background-color: var(--bg-secondary);
+ padding: .4em;
+ cursor: pointer;
+}
+
+.load-more-btn:hover {
+ background-color: var(--text-primary);
+ color: var(--bg-main);
+}
+
.message-group {
display: flex;
flex-direction: column;