feat(chat): show unread message counter
This commit is contained in:
parent
33397055bb
commit
f5704fa13c
@ -91,11 +91,19 @@ defmodule Slax.Chat do
|
||||
Repo.all(query)
|
||||
end
|
||||
|
||||
def list_joined_rooms(%User{} = user) do
|
||||
user
|
||||
|> Repo.preload(:rooms)
|
||||
|> Map.fetch!(:rooms)
|
||||
|> Enum.sort_by(& &1.name)
|
||||
def list_joined_rooms_with_unread_count(%User{} = user) do
|
||||
query =
|
||||
from(room in Room,
|
||||
join: membership in assoc(room, :memberships),
|
||||
left_join: message in assoc(room, :messages),
|
||||
on: message.id > membership.last_read_id,
|
||||
where: membership.user_id == ^user.id,
|
||||
group_by: room.id,
|
||||
select: %{room | unread_message_count: count(message.id)},
|
||||
order_by: [asc: room.name]
|
||||
)
|
||||
|
||||
Repo.all(query)
|
||||
end
|
||||
|
||||
def list_rooms_with_joined(%User{} = user) do
|
||||
|
@ -8,9 +8,11 @@ defmodule Slax.Chat.Room do
|
||||
schema "rooms" do
|
||||
field :name, :string
|
||||
field :topic, :string
|
||||
field :unread_message_count, :integer, virtual: true, default: 0
|
||||
|
||||
many_to_many :members, User, join_through: RoomMembership
|
||||
|
||||
has_many :memberships, RoomMembership
|
||||
has_many :messages, Message
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
|
@ -63,7 +63,7 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
<div class="flex justify-between items-center flex-shrink-0 h-16 bg-white border-b border-slate-300 px-4">
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<h1 class="text-sm font-bold leading-none">
|
||||
#<%= @room.name %>
|
||||
#{@room.name}
|
||||
<.link
|
||||
:if={@joined?}
|
||||
class="font-normal text-xs text-blue-600 hover:text-blue-700"
|
||||
@ -76,14 +76,14 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
<%= if @hide_topic? do %>
|
||||
<span class="text-slate-600">[Topic hidden]</span>
|
||||
<% else %>
|
||||
<%= @room.topic %>
|
||||
{@room.topic}
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="relative z-10 flex items-center gap-4 px-4 sm:px-6 lg:px-8 justify-end">
|
||||
<%= if @current_user do %>
|
||||
<li class="text-[0.8125rem] leading-6 text-zinc-900">
|
||||
<%= username(@current_user) %>
|
||||
{username(@current_user)}
|
||||
</li>
|
||||
<li>
|
||||
<.link
|
||||
@ -173,8 +173,8 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
>
|
||||
<div class="max-w-3-xl text-center">
|
||||
<div class="mb-4">
|
||||
<h1 class="text-xl font-semibold"><%= @room.name %></h1>
|
||||
<p :if={@room.topic} class="text-sm mt-1 text-gray-600"><%= @room.topic %></p>
|
||||
<h1 class="text-xl font-semibold">{@room.name}</h1>
|
||||
<p :if={@room.topic} class="text-sm mt-1 text-gray-600">{@room.topic}</p>
|
||||
</div>
|
||||
<div class="flex items-center justify-around">
|
||||
<buttom
|
||||
@ -201,7 +201,7 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
|
||||
@impl Phoenix.LiveView
|
||||
def mount(_params, _session, socket) do
|
||||
rooms = Chat.list_joined_rooms(socket.assigns.current_user)
|
||||
rooms = Chat.list_joined_rooms_with_unread_count(socket.assigns.current_user)
|
||||
users = Accounts.list_users()
|
||||
|
||||
timezone = get_connect_params(socket)["timezone"]
|
||||
@ -212,6 +212,8 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
|
||||
OnlineUsers.subscribe()
|
||||
|
||||
Enum.each(rooms, &Chat.subscribe_to_room/1)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(
|
||||
@ -233,8 +235,6 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
|
||||
@impl Phoenix.LiveView
|
||||
def handle_params(params, _session, socket) do
|
||||
if socket.assigns[:room], do: Chat.unsubscribe_from_room(socket.assigns.room)
|
||||
|
||||
room =
|
||||
case Map.fetch(params, "id") do
|
||||
{:ok, id} ->
|
||||
@ -248,8 +248,6 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
|
||||
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,
|
||||
@ -262,7 +260,18 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
)
|
||||
|> stream(:messages, messages, reset: true)
|
||||
|> assign_message_form(Chat.change_message(%Message{}))
|
||||
|> push_event("scroll_messages_to_bottom", %{})}
|
||||
|> push_event("scroll_messages_to_bottom", %{})
|
||||
|> update(:rooms, fn rooms ->
|
||||
room_id = room.id
|
||||
|
||||
Enum.map(rooms, fn
|
||||
%Room{id: ^room_id} = room ->
|
||||
%Room{room | unread_message_count: 0}
|
||||
|
||||
other_room ->
|
||||
other_room
|
||||
end)
|
||||
end)}
|
||||
end
|
||||
|
||||
@impl Phoenix.LiveView
|
||||
@ -309,20 +318,42 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
room = socket.assigns.room
|
||||
Chat.join_room!(room, current_user)
|
||||
Chat.subscribe_to_room(room)
|
||||
socket = assign(socket, joined?: true, rooms: Chat.list_joined_rooms(current_user))
|
||||
|
||||
socket =
|
||||
assign(socket, joined?: true, rooms: Chat.list_joined_rooms_with_unread_count(current_user))
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
@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
|
||||
room = socket.assigns.room
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> stream_insert(:messages, message)
|
||||
|> push_event("scroll_messages_to_bottom", %{})
|
||||
cond do
|
||||
message.room_id == room.id ->
|
||||
Chat.update_last_read_id(room, socket.assigns.current_user)
|
||||
|
||||
socket
|
||||
|> stream_insert(:messages, message)
|
||||
|> push_event("scroll_messages_to_bottom", %{})
|
||||
|
||||
message.user_id != socket.assigns.current_user.id ->
|
||||
update(socket, :rooms, fn rooms ->
|
||||
room_id = message.room_id
|
||||
|
||||
Enum.map(rooms, fn
|
||||
%Room{id: ^room_id} = room ->
|
||||
%Room{room | unread_message_count: room.unread_message_count + 1}
|
||||
|
||||
other_room ->
|
||||
other_room
|
||||
end)
|
||||
end)
|
||||
|
||||
true ->
|
||||
socket
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
@ -353,12 +384,26 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
>
|
||||
<.icon name="hero-hashtag" class="h-4 w-4" />
|
||||
<span class={["ml-2 leading-none", @active && "font-bold"]}>
|
||||
<%= @room.name %>
|
||||
{@room.name}
|
||||
</span>
|
||||
<.unread_message_count count={@room.unread_message_count} />
|
||||
</.link>
|
||||
"""
|
||||
end
|
||||
|
||||
attr :count, :integer, required: true
|
||||
|
||||
defp unread_message_count(assigns) do
|
||||
~H"""
|
||||
<span
|
||||
:if={@count > 0}
|
||||
class="flex items-center justifiy-center bg-blue-500 rounded-full font-medium h-5 px-2 ml-auto text-xs text-white"
|
||||
>
|
||||
{@count}
|
||||
</span>
|
||||
"""
|
||||
end
|
||||
|
||||
attr :user, User, required: true
|
||||
attr :online, :boolean, default: false
|
||||
|
||||
@ -372,7 +417,7 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
<span class="w-2 h-2 rounded-full border-2 border-gray-500"></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<span class="ml-2 leading-none"><%= username(@user) %></span>
|
||||
<span class="ml-2 leading-none">{username(@user)}</span>
|
||||
</.link>
|
||||
"""
|
||||
end
|
||||
@ -398,12 +443,12 @@ defmodule SlaxWeb.ChatRoomLive do
|
||||
<div class="ml-2">
|
||||
<div class="-mt-1">
|
||||
<.link class="text-sm font-semibold hover:underline">
|
||||
<span><%= username(@message.user) %></span>
|
||||
<span>{username(@message.user)}</span>
|
||||
</.link>
|
||||
<span :if={@timezone} class="ml-1 text-xs text-gray-500">
|
||||
<%= message_timestamp(@message, @timezone) %>
|
||||
{message_timestamp(@message, @timezone)}
|
||||
</span>
|
||||
<p class="text-sm"><%= @message.body %></p>
|
||||
<p class="text-sm">{@message.body}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user