refactor: some work to get initial page load working a bit better

This commit is contained in:
Andy Burke 2025-07-04 13:08:00 -07:00
parent 200b89954b
commit f276fe74da
3 changed files with 98 additions and 41 deletions

View file

@ -26,22 +26,31 @@
## TODO ## TODO
- [ ] should everything be an event in a room?
- [X] sign up - [X] sign up
- [X] check for logged in user session - [X] check for logged in user session
- [X] log in - [X] log in
- [X] chat rooms - [X] chat rooms
- [ ] gif support
- [ ] media uploads
- [ ] local upload support (keep it simple for small instances)
- [ ] S3 support (then self-host with your friends: https://garagehq.deuxfleurs.fr/)
- [ ] try to select immediate sibling messages from the same user and hide mulitple avatars
- [X] chat messages - [X] chat messages
- [ ] bulletin board instead of exchange/work? - [X] user profile page
- [ ] should everything be an event in a room? - [ ] profile editing
- [ ] post-it style notes with tag and keyword filtering? - [ ] avatar uploads
- [ ] local upload support (keep it simple for small instances)
- [ ] S3 support (then self-host with your friends: https://garagehq.deuxfleurs.fr/)
- [ ] admin panel
- [ ] add invite code generation
- [ ] AC_REQUIRE_INVITE_CODE: boolean env var/setting
- [ ] AC_DIRECTORY_SERVERS: |-separated list of directory servers to report to
these central servers could be distributed directories - your town might run one,
your state, your country, or you could publish to a public one that is organized
around interests
- [ ] combined "bulletin board" instead of exchange/work?
- [ ] post-it style notes with tag and keyword filtering?
- [ ] simple wiki for resources - [ ] simple wiki for resources
- [ ] simple calendar with public/private event tracking - [ ] simple calendar with public/private event tracking
- [ ] caldav support? - [ ] caldav support
- [ ] add an optional env var where you can specify a list of
"directory servers" (;-separated urls?) to ping with this
server's existence - the idea being these central servers
could be distributed directories - your town might run one,
your state, your country, or you could publish to a public
one that is organized around interests
- [X] user profile page
- [ ] user profile editing

View file

@ -2,7 +2,13 @@
window.addEventListener("locationchange", () => { window.addEventListener("locationchange", () => {
const hash = window.location.hash?.slice(1); const hash = window.location.hash?.slice(1);
if (hash) { if (hash) {
const target_tab = document.querySelector(`[data-hash="${hash}"]`); const target_tab_url = hash.slice(0, hash.slice(1).indexOf("/"));
const target_tab = document.querySelector(`[data-hash="${target_tab_url}"]`);
console.dir({
hash,
target_tab_url,
target_tab,
});
if (target_tab) { if (target_tab) {
target_tab.click(); target_tab.click();
} }

View file

@ -193,7 +193,22 @@
async function append_room_events(events) { async function append_room_events(events) {
const room_chat_content = document.getElementById("room-chat-content"); const room_chat_content = document.getElementById("room-chat-content");
const users = {}; const users = {};
let last_message_id = undefined;
for (const event of events) { for (const event of events) {
// if the last message is undefined, it becomes this event, otherwise, if this event's id is newer,
// it becomes the latest message
last_message_id =
last_message_id === undefined
? event.id
: event.id > last_message_id
? event.id
: last_message_id;
// if the last message has been updated, update the content's dataset to reflect that
if (last_message_id !== room_chat_content.dataset.last_message_id) {
room_chat_content.dataset.last_message_id = last_message_id;
}
users[event.creator_id] = users[event.creator_id] =
users[event.creator_id] ?? users[event.creator_id] ??
(await api.fetch(`/users/${event.creator_id}`)); (await api.fetch(`/users/${event.creator_id}`));
@ -203,13 +218,11 @@
render_text_event(event, users[event.creator_id]), render_text_event(event, users[event.creator_id]),
); );
} }
console.dir({
users,
events,
room_chat_content,
});
} }
// TODO: we need some abortcontroller handling here or something
// similar for when we change rooms, this is the most basic
// first pass outline
let room_polling_request_abort_controller = null; let room_polling_request_abort_controller = null;
async function poll_for_new_events() { async function poll_for_new_events() {
const room_chat_content = document.getElementById("room-chat-content"); const room_chat_content = document.getElementById("room-chat-content");
@ -222,7 +235,6 @@
signal: room_polling_request_abort_controller.signal, signal: room_polling_request_abort_controller.signal,
}) })
.then((new_events) => { .then((new_events) => {
const room;
append_room_events(new_events); append_room_events(new_events);
poll_for_new_events(room_id); poll_for_new_events(room_id);
}) })
@ -236,7 +248,7 @@
if (room_polling_request_abort_controller) { if (room_polling_request_abort_controller) {
room_polling_request_abort_controller.abort(); room_polling_request_abort_controller.abort();
room_polling_request_abort_controller = null; room_polling_request_abort_controller = null;
last_message_id = null; delete room_chat_content.dataset.last_message_id;
} }
const room_response = await api.fetch(`/rooms/${room_id}`); const room_response = await api.fetch(`/rooms/${room_id}`);
@ -249,8 +261,17 @@
const room = await room_response.json(); const room = await room_response.json();
const room_chat_content = document.getElementById("room-chat-content"); const room_chat_content = document.getElementById("room-chat-content");
room_chat_content.dataset.room_id = room.id;
room_chat_content.innerHTML = ""; room_chat_content.innerHTML = "";
const room_selectors = document.querySelectorAll("li.room");
for (const room_selector of room_selectors) {
room_selector.classList.remove("active");
if (room_selector.id === `room-selector-${room_id}`) {
room_selector.classList.add("active");
}
}
const events_response = await api.fetch( const events_response = await api.fetch(
`/rooms/${room_id}/events?type=chat&limit=100&sort=newest`, `/rooms/${room_id}/events?type=chat&limit=100&sort=newest`,
); );
@ -265,32 +286,17 @@
append_room_events(events); append_room_events(events);
last_message_id = events.length ? events[events.length - 1].id : null; last_message_id = events.length ? events[events.length - 1].id : null;
room_polling_request_abort_controller = new AbortController();
poll_for_new_events(room_id); poll_for_new_events(room_id);
} }
// TODO: one place to handle switching rooms let last_room_update = undefined;
// TODO: load events when we switch rooms and clear and update the chat async function update_chat_rooms() {
// TODO: try to select immediate siblings from the same user and hide avatars const now = new Date();
function check_for_room_in_url() { const time_since_last_update = now - (last_room_update ?? 0);
const hash = window.location.hash; if (time_since_last_update < 5_000) {
const room_id = return;
hash.indexOf("#/talk/room/") === 0 ? hash.substring(12) : "";
const room_chat_container = document.getElementById("room-chat-container");
room_chat_container.dataset.room_id = room_id;
const room_selectors = document.querySelectorAll("li.room");
for (const room_selector of room_selectors) {
room_selector.classList.remove("active");
} }
const room_selector = document.getElementById(`room-selector-${room_id}`);
room_selector.classList.add("active");
load_room(room_id);
}
window.addEventListener("locationchange", check_for_room_in_url);
document.addEventListener("DOMContentLoaded", async () => {
const rooms_response = await api.fetch("/rooms"); const rooms_response = await api.fetch("/rooms");
if (rooms_response.ok) { if (rooms_response.ok) {
const room_list = document.getElementById("room-list"); const room_list = document.getElementById("room-list");
@ -302,8 +308,44 @@
`<li id="room-selector-${room.id}" class="room"><a href="#/talk/room/${room.id}">${room.name}</a></li>`, `<li id="room-selector-${room.id}" class="room"><a href="#/talk/room/${room.id}">${room.name}</a></li>`,
); );
} }
last_room_update = now;
}
}
window.addEventListener("locationchange", update_chat_rooms);
function check_for_room_in_url() {
const hash = window.location.hash;
const talk_in_url = hash.indexOf("#/talk") === 0;
if (!talk_in_url) {
return;
} }
const first_room_id = document.querySelector("li.room")?.id.substring(14);
// #/talk/room/{room_id}
// ^ 12
const room_id = hash.substring(12) || first_room_id;
if (!room_id) {
alert("failed to load chat room!");
return;
}
const room_chat_container = document.getElementById("room-chat-container");
room_chat_container.dataset.room_id = room_id;
load_room(room_id);
}
window.addEventListener("locationchange", check_for_room_in_url);
document.addEventListener("DOMContentLoaded", async () => {
await update_chat_rooms();
check_for_room_in_url();
});
// TODO: this should be moved to be handled by a smartform
document.addEventListener("DOMContentLoaded", async () => {
const chat_input = document.getElementById("room-chat-input"); const chat_input = document.getElementById("room-chat-input");
async function on_send_message(event) { async function on_send_message(event) {
event.preventDefault(); event.preventDefault();