feat(chat): add unread message divider

This commit is contained in:
João Paulo Dubas 2024-11-25 23:22:31 +00:00
parent 24c457413d
commit 2430b41ce1
Signed by: joao.dubas
SSH Key Fingerprint: SHA256:V1mixgOGRc/YMhGx/DNkOSmJxgA2vHNrDZEk3wt/kOA
4 changed files with 88 additions and 10 deletions

View File

@ -3,6 +3,7 @@ defmodule Slax.Chat do
Context to handle with chat details.
"""
import Ecto.Changeset
import Ecto.Query
alias Slax.Accounts.User
@ -36,7 +37,7 @@ defmodule Slax.Chat do
end
def toggle_room_membership(%Room{} = room, %User{} = user) do
case Repo.get_by(RoomMembership, room_id: room.id, user_id: user.id) do
case get_membership(room, user) do
%RoomMembership{} = membership ->
Repo.delete(membership)
{room, false}
@ -47,6 +48,31 @@ defmodule Slax.Chat do
end
end
def update_last_read_id(%Room{} = room, %User{} = user) do
case get_membership(room, user) do
%RoomMembership{} = membership ->
query = from(m in Message, where: m.room_id == ^room.id, select: max(m.id))
id = Repo.one(query)
membership
|> change(%{last_read_id: id})
|> Repo.update()
nil ->
nil
end
end
def get_last_read_id(%Room{} = room, %User{} = user) do
case get_membership(room, user) do
%RoomMembership{} = membership ->
membership.last_read_id
nil ->
nil
end
end
def change_room(room, attrs \\ %{}) do
Room.changeset(room, attrs)
end
@ -131,4 +157,8 @@ defmodule Slax.Chat do
defp topic(%Room{id: room_id}), do: "chat_room:#{room_id}"
defp topic(room_id), do: topic(%Room{id: room_id})
defp get_membership(%Room{} = room, %User{} = user) do
Repo.get_by(RoomMembership, room_id: room.id, user_id: user.id)
end
end

View File

@ -6,6 +6,8 @@ defmodule Slax.Chat.RoomMembership do
alias Slax.Chat.Room
schema "room_memberships" do
field :last_read_id, :integer
belongs_to :room, Room
belongs_to :user, User

View File

@ -128,13 +128,21 @@ defmodule SlaxWeb.ChatRoomLive do
phx-hook="RoomMessages"
phx-update="stream"
>
<.message
:for={{dom_id, message} <- @streams.messages}
current_user={@current_user}
dom_id={dom_id}
message={message}
timezone={@timezone}
/>
<%= for {dom_id, message} <- @streams.messages do %>
<%= if message == :unread_marker do %>
<div id={dom_id} class="w-full flex text-red-500 items-center gap-3 pr-5">
<div class="w-full h-px grow bg-red-500"></div>
<div class="text-sm">New</div>
</div>
<% else %>
<.message
current_user={@current_user}
dom_id={dom_id}
message={message}
timezone={@timezone}
/>
<% end %>
<% end %>
</div>
<div :if={@joined?} class="h-12 bg-white px-4 pb-4">
<.form
@ -205,13 +213,20 @@ defmodule SlaxWeb.ChatRoomLive do
OnlineUsers.subscribe()
socket =
assign(socket,
socket
|> assign(
hide_topic?: false,
online_users: OnlineUsers.list(),
rooms: rooms,
timezone: timezone,
users: users
)
|> stream_configure(:messages,
dom_id: fn
%Message{id: id} -> "messages-#{id}"
:unread_marker -> "messages-unread-marker"
end
)
{:ok, socket}
end
@ -229,10 +244,14 @@ defmodule SlaxWeb.ChatRoomLive do
Chat.get_first_room!()
end
messages = Chat.list_messages_in_room(room)
last_read_id = Chat.get_last_read_id(room, socket.assigns.current_user)
messages = room |> Chat.list_messages_in_room() |> maybe_insert_unread_marker(last_read_id)
Chat.subscribe_to_room(room)
Chat.update_last_read_id(room, socket.assigns.current_user)
{:noreply,
socket
|> assign(
@ -296,6 +315,10 @@ defmodule SlaxWeb.ChatRoomLive do
@impl Phoenix.LiveView
def handle_info({:new_message, message}, socket) do
if message.room_id == socket.assigns.room.id do
Chat.update_last_read_id(message.room, socket.assigns.current_user)
end
socket =
socket
|> stream_insert(:messages, message)
@ -400,4 +423,18 @@ defmodule SlaxWeb.ChatRoomLive do
defp assign_message_form(socket, changeset) do
assign(socket, :new_message_form, to_form(changeset))
end
defp maybe_insert_unread_marker(messages, nil) do
messages
end
defp maybe_insert_unread_marker(messages, last_read_id) do
{read, unread} = Enum.split_while(messages, &(&1.id <= last_read_id))
if unread == [] do
read
else
read ++ [:unread_marker | unread]
end
end
end

View File

@ -0,0 +1,9 @@
defmodule Slax.Repo.Migrations.AlterRoomMembershipsAddLastReadId do
use Ecto.Migration
def change do
alter table(:room_memberships) do
add :last_read_id, :integer
end
end
end