feat: use pubsub to sync states

This commit is contained in:
Moritz Böhme 2025-04-08 11:58:37 +02:00
parent e72f6f29c1
commit 8de0f1e39f
3 changed files with 66 additions and 15 deletions

View file

@ -1,6 +1,9 @@
defmodule PutzplanWeb.TaskLive.FormComponent do
use PutzplanWeb, :live_component
@pubsub_name Putzplan.PubSub
@pubsub_topic_tasks "tasks"
@impl true
def render(assigns) do
~H"""
@ -47,7 +50,8 @@ defmodule PutzplanWeb.TaskLive.FormComponent do
def handle_event("save", %{"task" => task_params}, socket) do
case AshPhoenix.Form.submit(socket.assigns.form, params: task_params) do
{:ok, task} ->
notify_parent({:saved, task |> Ash.load!(:due)})
task = Ash.load!(task, :due)
Phoenix.PubSub.broadcast(@pubsub_name, @pubsub_topic_tasks, {:upsert, task})
socket =
socket
@ -61,8 +65,6 @@ defmodule PutzplanWeb.TaskLive.FormComponent do
end
end
defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
defp assign_form(%{assigns: %{task: task}} = socket) do
form =
if task do

View file

@ -1,6 +1,13 @@
defmodule PutzplanWeb.TaskLive.Index do
use PutzplanWeb, :live_view
@pubsub_name Putzplan.PubSub
@pubsub_topic "tasks"
defp get_topic(id) do
"completed:" <> id
end
@impl true
def render(assigns) do
~H"""
@ -116,6 +123,8 @@ defmodule PutzplanWeb.TaskLive.Index do
@impl true
def mount(_params, _session, socket) do
if connected?(socket), do: Phoenix.PubSub.subscribe(@pubsub_name, @pubsub_topic)
{:ok,
socket
|> stream(
@ -130,12 +139,28 @@ defmodule PutzplanWeb.TaskLive.Index do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
@impl true
def handle_info({:delete, task}, socket) do
{:noreply, stream_delete(socket, :tasks, task)}
end
@impl true
def handle_info({:upsert, task}, socket) do
{:noreply, stream_insert(socket, :tasks, task)}
end
@impl true
def handle_info({:update, task_id}, socket) do
task = Ash.get!(Putzplan.Tasks.Task, task_id, load: [:due])
{:noreply, stream_insert(socket, :tasks, task)}
end
defp apply_action(socket, :edit, %{"id" => id}) do
socket
|> assign(:page_title, "Edit Task")
|> assign(
:task,
Ash.get!(Putzplan.Tasks.Task, id, load: [:due], actor: socket.assigns.current_user)
Ash.get!(Putzplan.Tasks.Task, id, actor: socket.assigns.current_user)
)
end
@ -151,31 +176,35 @@ defmodule PutzplanWeb.TaskLive.Index do
|> assign(:task, nil)
end
@impl true
def handle_info({PutzplanWeb.TaskLive.FormComponent, {:saved, task}}, socket) do
{:noreply, stream_insert(socket, :tasks, task)}
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
task = Ash.get!(Putzplan.Tasks.Task, id, actor: socket.assigns.current_user)
Ash.destroy!(task, actor: socket.assigns.current_user)
Phoenix.PubSub.broadcast(@pubsub_name, @pubsub_topic, {:delete, task})
{:noreply, stream_delete(socket, :tasks, task)}
{:noreply, task}
end
@impl true
def handle_event("complete", %{"id" => id}, socket) do
Putzplan.Tasks.CompletedTask
|> Ash.Changeset.for_create(:create, %{task: id, user: socket.assigns.current_user.id})
|> Ash.create!(actor: socket.assigns.current_user)
completed_task =
Putzplan.Tasks.CompletedTask
|> Ash.Changeset.for_create(:create, %{task: id, user: socket.assigns.current_user.id})
|> Ash.create!(actor: socket.assigns.current_user)
{:noreply, stream_insert(socket, :tasks, Ash.get!(Putzplan.Tasks.Task, id, load: [:due]))}
task = Ash.get!(Putzplan.Tasks.Task, id, load: [:due])
Phoenix.PubSub.broadcast(@pubsub_name, @pubsub_topic, {:upsert, task})
Phoenix.PubSub.broadcast(@pubsub_name, get_topic(id), {:upsert, completed_task})
{:noreply, socket}
end
defp format_date(date) do
string =
case Date.diff(date, Date.utc_today()) do
-1 ->
"yesterday"
0 ->
"today"

View file

@ -2,6 +2,12 @@ defmodule PutzplanWeb.TaskLive.Show do
require Ash.Query
use PutzplanWeb, :live_view
@pubsub_name Putzplan.PubSub
defp get_topic(id) do
"completed:" <> id
end
@impl true
def render(assigns) do
~H"""
@ -90,7 +96,8 @@ defmodule PutzplanWeb.TaskLive.Show do
end
@impl true
def mount(_params, _session, socket) do
def mount(%{"id" => id}, _session, socket) do
if connected?(socket), do: Phoenix.PubSub.subscribe(@pubsub_name, get_topic(id))
{:ok, socket}
end
@ -120,6 +127,19 @@ defmodule PutzplanWeb.TaskLive.Show do
Ash.destroy!(completed_task, actor: socket.assigns.current_user)
Phoenix.PubSub.broadcast!(@pubsub_name, get_topic(id), {:delete, completed_task})
Phoenix.PubSub.broadcast!(@pubsub_name, "tasks", {:update, completed_task.tasks.id})
{:noreply, socket}
end
@impl true
def handle_info({:delete, completed_task}, socket) do
{:noreply, stream_delete(socket, :completed_tasks, completed_task)}
end
@impl true
def handle_info({:upsert, completed_task}, socket) do
{:noreply, stream_insert(socket, :completed_tasks, completed_task)}
end
end