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

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New

Other popular topics Top

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
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49084 226
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement