defmodule RiverConnectWeb.AudioLive do use RiverConnectWeb, :live_view alias RiverConnect.Audio @impl true def mount(_params, _session, socket) do if connected?(socket) do RiverConnectWeb.Endpoint.subscribe("audio:lobby") end # Fetch initial messages messages = Audio.list_messages() {:ok, assign(socket, messages: messages, recording: false, page_title: "Voxer Audio")} end @impl true def handle_event("recording_started", %{"id" => _id}, socket) do {:noreply, assign(socket, recording: true)} end @impl true def handle_event("recording_stopped", _params, socket) do {:noreply, assign(socket, recording: false)} end @impl true def handle_info(%{event: "audio_message_created", payload: %{message: message}}, socket) do # Prepend new message messages = [message | socket.assigns.messages] {:noreply, assign(socket, messages: messages)} end @impl true def handle_info(%{event: "audio_message_ready", payload: %{id: _id}}, socket) do # Reload message to get updated status/path # In a real app we'd update just the one message, here we refresh all for simplicity messages = Audio.list_messages() {:noreply, assign(socket, messages: messages)} end # Forward other broadcasts (like chunks) which are handled by JS, but if they come here we ignore @impl true def handle_info(_, socket), do: {:noreply, socket} @impl true def render(assigns) do ~H"""

Voxer Clone

Recent Messages

<%= if Enum.empty?(@messages) do %>

No messages yet. Start talking!

<% end %> <%= for message <- @messages do %>
{message.user_id} {Calendar.strftime(message.inserted_at, "%H:%M:%S")}
<%= if message.status == "ready" do %>
{message.duration_ms}ms
<% else %>
<%= if message.status == "recording" do %> 🔴 LIVE <% else %> Processing... <% end %>
<% end %>
<% end %>

if(@recording, do: "text-red-600", else: "text-gray-600")}> {if @recording, do: "Click to finish", else: "Click to Talk"}

""" end end