jam

jam

Showing unread indicators / counts for a chat app using Phoenix channels

I’m using Phoenix channels to build a chat app similar to Discord. I’m new to Elixir and Phoenix and wouldn’t consider myself to be a backend wizard. I’m wondering how you might handle showing unread indicators / counts.

Let’s assume a user belongs to multiple organizations and each of those has multiple rooms. Similar to Discord, I’d like be able to show:

  1. An unread dot next to each organization with unreads
  2. Bold the name of the unread room within an organization

I’ve set up my channels like this:

channel "user:*", AppWeb.UserChannel

channel "org:*", AppWeb.OrgChannel

channel "room:*", AppWeb.RoomChannel

I have a somewhat working solution but it feels a bit hacky so I’m wondering what a best practice solution might look like. Currently, I’m doing this:

  1. I have organizations, rooms, messages, org_memberships and room_memberships tables.
  2. I store a last_read_message_id on the room_memberships table and use it in my ecto queries.
  3. When the user logs in, I join them to the UserChannel which fetches their organizations and each has a virtualized boolean field for unread.
  4. When the user navigates to an organization, I join them to the OrgChannel which fetches the rooms for that organization and each has a virtualized field for unread_count. I assign the rooms to the socket.
  5. When the user navigates to a room, I join them to the RoomChannel which fetches the messages for that room.
  6. When a user sends a message, I determine which users should receive that message and use Phoenix.PubSub to broadcast that back to their respective UserChannel to update the organization boolean unread field and to the OrgChannel to increment the unread_count for that room if it’s found in the socket’s rooms. These are both pushed to the client so that I can show the unread indicators as described above.

My solution also seems to kind of hit a roadblock when taking into account direct messages because they aren’t tied to a particular organization. Right now a direct message is treated the same as a regular room but with type: “dm” and organization_id: null. Open to ideas here too.

I considered sending the unread_count for all rooms a user is a member of after they log in but that seemed like a bad idea if they are in say 20+ organizations each with 20+ rooms. Maybe my intuition here is wrong and it’s ok as long as the payload is small with just the room_id, organization_id, and the unread_count?

I’m guessing this is well-trodden territory and would appreciate any tips you might have.

Where Next?

Popular in Questions Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54921 245
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42533 114
New

We're in Beta

About us Mission Statement