defmodule SlaxWeb.ChatRoomLive do @moduledoc false use SlaxWeb, :live_view require Logger alias Slax.Accounts alias Slax.Accounts.User alias Slax.Chat alias Slax.Chat.Message alias Slax.Chat.Room alias SlaxWeb.OnlineUsers @impl Phoenix.LiveView def render(assigns) do ~H"""

Slax

Rooms
<.room_link :for={room <- @rooms} room={room} active={room.id == @room.id} />
Users
<.user :for={user <- @users} user={user} online={OnlineUsers.online?(@online_users, user.id)} />

#<%= @room.name %> <.link class="font-normal text-xs text-blue-600 hover:text-blue-700" navigate={~p"/rooms/#{@room}/edit"} > Edit

<%= if @hide_topic? do %> [Topic hidden] <% else %> <%= @room.topic %> <% end %>
<.message :for={{dom_id, message} <- @streams.messages} current_user={@current_user} dom_id={dom_id} message={message} timezone={@timezone} />
<.form id="new-message-form" for={@new_message_form} phx-change="validate-message" phx-submit="submit-message" class="flex items-center border-2 border-slate-300 rounded-sm p-1" >
""" end @impl Phoenix.LiveView def mount(_params, _session, socket) do rooms = Chat.list_rooms() users = Accounts.list_users() timezone = get_connect_params(socket)["timezone"] if connected?(socket) do OnlineUsers.track(self(), socket.assigns.current_user) end OnlineUsers.subscribe() socket = assign(socket, hide_topic?: false, online_users: OnlineUsers.list(), rooms: rooms, timezone: timezone, users: users ) {:ok, socket} end @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} -> Chat.get_room!(id) :error -> Chat.get_first_room!() end messages = Chat.list_messages_in_room(room) Chat.subscribe_to_room(room) {:noreply, socket |> assign(hide_topic?: false, page_title: "# #{room.name}", room: room) |> stream(:messages, messages, reset: true) |> assign_message_form(Chat.change_message(%Message{})) |> push_event("scroll_messages_to_bottom", %{})} end @impl Phoenix.LiveView def handle_event("toggle-topic", _params, socket) do {:noreply, update(socket, :hide_topic?, &(!&1))} end @impl Phoenix.LiveView def handle_event("validate-message", %{"message" => message_params}, socket) do changeset = Chat.change_message(%Message{}, message_params) {:noreply, assign_message_form(socket, changeset)} end @impl Phoenix.LiveView def handle_event("submit-message", %{"message" => message_params}, socket) do %{current_user: user, room: room} = socket.assigns socket = case Chat.create_message(room, user, message_params) do {:ok, _message} -> assign_message_form(socket, Chat.change_message(%Message{})) {:error, changeset} -> assign_message_form(socket, changeset) end {:noreply, socket} end @impl Phoenix.LiveView def handle_event("delete-message", %{"id" => message_id}, socket) do Chat.delete_message_by_id(message_id, socket.assigns.current_user) {:noreply, socket} end @impl Phoenix.LiveView def handle_info({:new_message, message}, socket) do socket = socket |> stream_insert(:messages, message) |> push_event("scroll_messages_to_bottom", %{}) {:noreply, socket} end @impl Phoenix.LiveView def handle_info({:deleted_message, message}, socket) do {:noreply, stream_delete(socket, :messages, message)} end @impl Phoenix.LiveView def handle_info(%{event: "presence_diff", payload: diff}, socket) do online_users = OnlineUsers.update(socket.assigns.online_users, diff) {:noreply, assign(socket, online_users: online_users)} end attr :active, :boolean, required: true attr :room, Room, required: true @spec room_link(Phoenix.LiveView.Socket.assigns()) :: Phoenix.LiveView.Rendered.t() defp room_link(assigns) do ~H""" <.link class={[ "flex items-center h-8 text-sm pl-8 pr-3", (@active && "bg-slate-300") || "hover:bg-slate-300" ]} patch={~p"/rooms/#{@room}"} > <.icon name="hero-hashtag" class="h-4 w-4" /> <%= @room.name %> """ end attr :user, User, required: true attr :online, :boolean, default: false defp user(assigns) do ~H""" <.link class="flex items-center h-8 hover:bg-gray-300 text-sm pl-8 pr-3" href="#">
<%= if @online do %> <% else %> <% end %>
<%= username(@user) %> """ end attr :current_user, User, required: true attr :dom_id, :string, required: true attr :message, Message, required: true attr :timezone, :string, required: true defp message(assigns) do ~H"""
<.link class="text-sm font-semibold hover:underline"> <%= username(@message.user) %> <%= message_timestamp(@message, @timezone) %>

<%= @message.body %>

""" end defp username(user) do user.email |> String.split("@") |> List.first() |> String.capitalize() end defp message_timestamp(message, timezone) do message.inserted_at |> Timex.Timezone.convert(timezone) |> Timex.format!("%-l:%M %p", :strftime) end defp assign_message_form(socket, changeset) do assign(socket, :new_message_form, to_form(changeset)) end end