From 70aeb019a525786de0fb4c58e2a458453253ff43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Mon, 7 Apr 2025 11:22:44 +0200 Subject: [PATCH 01/10] feat: allow completing tasks and deleting completions --- lib/putzplan/tasks/completed_task.ex | 6 +-- .../live/task_live/form_component.ex | 3 +- lib/putzplan_web/live/task_live/index.ex | 38 +++++++++++-------- lib/putzplan_web/live/task_live/show.ex | 31 +++++++-------- 4 files changed, 41 insertions(+), 37 deletions(-) diff --git a/lib/putzplan/tasks/completed_task.ex b/lib/putzplan/tasks/completed_task.ex index 44ac3a6..c94e59b 100644 --- a/lib/putzplan/tasks/completed_task.ex +++ b/lib/putzplan/tasks/completed_task.ex @@ -2,7 +2,7 @@ defmodule Putzplan.Tasks.CompletedTask do use Ash.Resource, otp_app: :putzplan, domain: Putzplan.Tasks, data_layer: AshSqlite.DataLayer actions do - defaults [:read] + defaults [:destroy] read :read_with_relations do primary? true @@ -13,8 +13,8 @@ defmodule Putzplan.Tasks.CompletedTask do create :create do primary? true - argument :user, :map, allow_nil?: false - argument :task, :map, allow_nil?: false + argument :user, :uuid, allow_nil?: false + argument :task, :uuid, allow_nil?: false change set_attribute(:completion, &Date.utc_today/0) change manage_relationship(:user, :users, type: :append) diff --git a/lib/putzplan_web/live/task_live/form_component.ex b/lib/putzplan_web/live/task_live/form_component.ex index 346553a..7fd3d2f 100644 --- a/lib/putzplan_web/live/task_live/form_component.ex +++ b/lib/putzplan_web/live/task_live/form_component.ex @@ -17,7 +17,6 @@ defmodule PutzplanWeb.TaskLive.FormComponent do phx-change="validate" phx-submit="save" > - <.input field={@form[:description]} type="text" label="Description" /><.input field={@form[:repetition_days]} type="number" label="Repetition days" /> @@ -46,7 +45,7 @@ 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}) + notify_parent({:saved, task |> Ash.load!(:due)}) socket = socket diff --git a/lib/putzplan_web/live/task_live/index.ex b/lib/putzplan_web/live/task_live/index.ex index 964368a..efafbbb 100644 --- a/lib/putzplan_web/live/task_live/index.ex +++ b/lib/putzplan_web/live/task_live/index.ex @@ -18,20 +18,21 @@ defmodule PutzplanWeb.TaskLive.Index do rows={@streams.tasks} row_click={fn {_id, task} -> JS.navigate(~p"/tasks/#{task}") end} > - + <:col :let={{_id, task}} label="Description"><%= task.description %> - + <:col :let={{_id, task}} label="Due"><%= task.due %> - + <:action :let={{_id, task}}>
<.link navigate={~p"/tasks/#{task}"}>Show
- + <.link patch={~p"/tasks/#{task}/edit"}>Edit - + <.link phx-click={JS.push("complete", value: %{id: task.id})}>Complete + - + <:action :let={{id, task}}> <.link phx-click={JS.push("delete", value: %{id: task.id}) |> hide("##{id}")} @@ -40,24 +41,19 @@ defmodule PutzplanWeb.TaskLive.Index do Delete - + - - <.modal :if={@live_action in [:new, :edit]} id="task-modal" show on_cancel={JS.patch(~p"/tasks")}> <.live_component module={PutzplanWeb.TaskLive.FormComponent} id={(@task && @task.id) || :new} title={@page_title} - - current_user={@current_user} - + current_user={@current_user} action={@live_action} task={@task} - patch={~p"/tasks"} + patch={~p"/"} /> - """ end @@ -65,7 +61,10 @@ defmodule PutzplanWeb.TaskLive.Index do def mount(_params, _session, socket) do {:ok, socket - |> stream(:tasks, Ash.read!(Putzplan.Tasks.Task, load: [:due], actor: socket.assigns[:current_user])) + |> stream( + :tasks, + Ash.read!(Putzplan.Tasks.Task, load: [:due], actor: socket.assigns[:current_user]) + ) |> assign_new(:current_user, fn -> nil end)} end @@ -104,4 +103,13 @@ defmodule PutzplanWeb.TaskLive.Index do {:noreply, stream_delete(socket, :tasks, 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) + + {:noreply, stream_insert(socket, :tasks, Ash.get!(Putzplan.Tasks.Task, id, load: [:due]))} + end end diff --git a/lib/putzplan_web/live/task_live/show.ex b/lib/putzplan_web/live/task_live/show.ex index 98c4d7a..0f04a92 100644 --- a/lib/putzplan_web/live/task_live/show.ex +++ b/lib/putzplan_web/live/task_live/show.ex @@ -21,25 +21,14 @@ defmodule PutzplanWeb.TaskLive.Show do > <:col :let={{_id, completed_task}} label="Completed by"><%= completed_task.users.name %> <:col :let={{_id, completed_task}} label="Date"><%= completed_task.completion %> + <:action :let={{id, completed_task}}> + <.link phx-click={JS.push("delete", value: %{id: completed_task.id}) |> hide("##{id}")}> + Delete + + - <.back navigate={~p"/tasks"}>Back to tasks - - - <.modal :if={@live_action == :edit} id="task-modal" show on_cancel={JS.patch(~p"/tasks/#{@task}")}> - <.live_component - module={PutzplanWeb.TaskLive.FormComponent} - id={@task.id} - title={@page_title} - action={@live_action} - - current_user={@current_user} - - task={@task} - patch={~p"/tasks/#{@task}"} - /> - - + <.back navigate={~p"/"}>Back to tasks """ end @@ -66,4 +55,12 @@ defmodule PutzplanWeb.TaskLive.Show do defp page_title(:show), do: "Show Task" defp page_title(:edit), do: "Edit Task" + + @impl true + def handle_event("delete", %{"id" => id}, socket) do + completed_task = Ash.get!(Putzplan.Tasks.CompletedTask, id, actor: socket.assigns.current_user) + Ash.destroy!(completed_task, actor: socket.assigns.current_user) + + {:noreply, stream_delete(socket, :completed_tasks, completed_task)} + end end From f34936b1761f442e75fd8ccc4e1da21f29ffb2cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Mon, 7 Apr 2025 15:03:53 +0200 Subject: [PATCH 02/10] style: formatter seems to work now --- .formatter.exs | 2 +- lib/putzplan/accounts/user.ex | 10 ++-- lib/putzplan/tasks/completed_task.ex | 10 ++-- lib/putzplan/tasks/task.ex | 52 +++++++++---------- lib/putzplan_web/auth_overrides.ex | 2 +- .../completed_task_live/form_component.ex | 11 ++-- .../live/completed_task_live/index.ex | 38 +++++++------- .../live/completed_task_live/show.ex | 11 ++-- .../live/task_live/form_component.ex | 12 +++-- lib/putzplan_web/live/task_live/index.ex | 49 +++++++++-------- lib/putzplan_web/live/task_live/show.ex | 36 ++++++------- 11 files changed, 117 insertions(+), 116 deletions(-) diff --git a/.formatter.exs b/.formatter.exs index cb2a852..2b73acd 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -10,6 +10,6 @@ :phoenix ], subdirectories: ["priv/*/migrations"], - # plugins: [Spark.Formatter, Phoenix.LiveView.HTMLFormatter], # FIXME:seems broken + plugins: [Spark.Formatter, Phoenix.LiveView.HTMLFormatter], inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"] ] diff --git a/lib/putzplan/accounts/user.ex b/lib/putzplan/accounts/user.ex index 0a57183..6540272 100644 --- a/lib/putzplan/accounts/user.ex +++ b/lib/putzplan/accounts/user.ex @@ -28,15 +28,11 @@ defmodule Putzplan.Accounts.User do client_secret "insecure_secret" nonce true redirect_uri "http://127.0.0.1:4000/auth" - authorization_params [scope: "profile email"] + authorization_params scope: "profile email" end end end - identities do - identity :id, [:id] - end - sqlite do table "users" repo Putzplan.Repo @@ -85,4 +81,8 @@ defmodule Putzplan.Accounts.User do uuid_primary_key :id, writable?: true, default: nil attribute :name, :string, allow_nil?: false end + + identities do + identity :id, [:id] + end end diff --git a/lib/putzplan/tasks/completed_task.ex b/lib/putzplan/tasks/completed_task.ex index c94e59b..c9b361f 100644 --- a/lib/putzplan/tasks/completed_task.ex +++ b/lib/putzplan/tasks/completed_task.ex @@ -1,6 +1,11 @@ defmodule Putzplan.Tasks.CompletedTask do use Ash.Resource, otp_app: :putzplan, domain: Putzplan.Tasks, data_layer: AshSqlite.DataLayer + sqlite do + table "completed_tasks" + repo Putzplan.Repo + end + actions do defaults [:destroy] @@ -41,9 +46,4 @@ defmodule Putzplan.Tasks.CompletedTask do source_attribute :task_id end end - - sqlite do - table "completed_tasks" - repo Putzplan.Repo - end end diff --git a/lib/putzplan/tasks/task.ex b/lib/putzplan/tasks/task.ex index 8914a89..0e7c35d 100644 --- a/lib/putzplan/tasks/task.ex +++ b/lib/putzplan/tasks/task.ex @@ -4,10 +4,36 @@ defmodule Putzplan.Tasks.Task do domain: Putzplan.Tasks, data_layer: AshSqlite.DataLayer + sqlite do + table "tasks" + repo Putzplan.Repo + end + actions do defaults [:read, :destroy, create: :*, update: :*] end + # Attributes are the simple pieces of data that exist on your resource + attributes do + # Add an autogenerated UUID primary key called `:id`. + uuid_primary_key :id + + attribute :description, :string do + allow_nil? false + public? true + end + + attribute :repetition_days, :integer do + allow_nil? false + public? true + constraints min: 1 + end + end + + relationships do + has_many :completed_tasks, Putzplan.Tasks.CompletedTask + end + calculations do calculate :last_completed, :date, @@ -32,30 +58,4 @@ defmodule Putzplan.Tasks.Task do ) ) end - - sqlite do - table "tasks" - repo Putzplan.Repo - end - - relationships do - has_many :completed_tasks, Putzplan.Tasks.CompletedTask - end - - # Attributes are the simple pieces of data that exist on your resource - attributes do - # Add an autogenerated UUID primary key called `:id`. - uuid_primary_key :id - - attribute :description, :string do - allow_nil? false - public? true - end - - attribute :repetition_days, :integer do - allow_nil? false - public? true - constraints min: 1 - end - end end diff --git a/lib/putzplan_web/auth_overrides.ex b/lib/putzplan_web/auth_overrides.ex index b25ed75..e9df549 100644 --- a/lib/putzplan_web/auth_overrides.ex +++ b/lib/putzplan_web/auth_overrides.ex @@ -15,6 +15,6 @@ defmodule PutzplanWeb.AuthOverrides do # end override AshAuthentication.Phoenix.Components.SignIn do - set :show_banner, false + set :show_banner, false end end diff --git a/lib/putzplan_web/live/completed_task_live/form_component.ex b/lib/putzplan_web/live/completed_task_live/form_component.ex index 5362db9..fc4f3ce 100644 --- a/lib/putzplan_web/live/completed_task_live/form_component.ex +++ b/lib/putzplan_web/live/completed_task_live/form_component.ex @@ -6,7 +6,7 @@ defmodule PutzplanWeb.CompletedTaskLive.FormComponent do ~H"""
<.header> - <%= @title %> + {@title} <:subtitle>Use this form to manage completed_task records in your database. @@ -17,9 +17,12 @@ defmodule PutzplanWeb.CompletedTaskLive.FormComponent do phx-change="validate" phx-submit="save" > - - <.input field={@form[:user]} type="text" label="User" /><.input field={@form[:task]} type="text" label="Task" /> - + <.input field={@form[:user]} type="text" label="User" /><.input + field={@form[:task]} + type="text" + label="Task" + /> + <:actions> <.button phx-disable-with="Saving...">Save Completed task diff --git a/lib/putzplan_web/live/completed_task_live/index.ex b/lib/putzplan_web/live/completed_task_live/index.ex index 5197afa..0db23d7 100644 --- a/lib/putzplan_web/live/completed_task_live/index.ex +++ b/lib/putzplan_web/live/completed_task_live/index.ex @@ -8,7 +8,7 @@ defmodule PutzplanWeb.CompletedTaskLive.Index do Listing Completed tasks <:actions> <.link patch={~p"/completed_tasks/new"}> - <.button>New Completed task + <.button>New Completed task @@ -18,31 +18,31 @@ defmodule PutzplanWeb.CompletedTaskLive.Index do rows={@streams.completed_tasks} row_click={fn {_id, completed_task} -> JS.navigate(~p"/completed_tasks/#{completed_task}") end} > - - <:col :let={{_id, completed_task}} label="Id"><%= completed_task.id %> - + <:col :let={{_id, completed_task}} label="Id">{completed_task.id} + <:action :let={{_id, completed_task}}>
<.link navigate={~p"/completed_tasks/#{completed_task}"}>Show
- - - - <.modal :if={@live_action == :new} id="completed_task-modal" show on_cancel={JS.patch(~p"/completed_tasks")}> - <.live_component - module={PutzplanWeb.CompletedTaskLive.FormComponent} - current_user={@current_user} - id={:new} - title={@page_title} - action={@live_action} - completed_task={@completed_task} - patch={~p"/completed_tasks"} - /> - - + <.modal + :if={@live_action == :new} + id="completed_task-modal" + show + on_cancel={JS.patch(~p"/completed_tasks")} + > + <.live_component + module={PutzplanWeb.CompletedTaskLive.FormComponent} + current_user={@current_user} + id={:new} + title={@page_title} + action={@live_action} + completed_task={@completed_task} + patch={~p"/completed_tasks"} + /> + """ end diff --git a/lib/putzplan_web/live/completed_task_live/show.ex b/lib/putzplan_web/live/completed_task_live/show.ex index f196e58..f8aa0d5 100644 --- a/lib/putzplan_web/live/completed_task_live/show.ex +++ b/lib/putzplan_web/live/completed_task_live/show.ex @@ -5,20 +5,15 @@ defmodule PutzplanWeb.CompletedTaskLive.Show do def render(assigns) do ~H""" <.header> - Completed task <%= @completed_task.id %> - <:subtitle>This is a completed_task record from your database. - + Completed task {@completed_task.id} + <:subtitle>This is a completed_task record from your database. <.list> - - <:item title="Id"><%= @completed_task.id %> - + <:item title="Id">{@completed_task.id} <.back navigate={~p"/completed_tasks"}>Back to completed_tasks - - """ end diff --git a/lib/putzplan_web/live/task_live/form_component.ex b/lib/putzplan_web/live/task_live/form_component.ex index 7fd3d2f..c0e212d 100644 --- a/lib/putzplan_web/live/task_live/form_component.ex +++ b/lib/putzplan_web/live/task_live/form_component.ex @@ -6,7 +6,7 @@ defmodule PutzplanWeb.TaskLive.FormComponent do ~H"""
<.header> - <%= @title %> + {@title} <:subtitle>Use this form to manage task records in your database. @@ -17,10 +17,12 @@ defmodule PutzplanWeb.TaskLive.FormComponent do phx-change="validate" phx-submit="save" > - - <.input field={@form[:description]} type="text" label="Description" /><.input field={@form[:repetition_days]} type="number" label="Repetition days" /> - - + <.input field={@form[:description]} type="text" label="Description" /><.input + field={@form[:repetition_days]} + type="number" + label="Repetition days" + /> + <:actions> <.button phx-disable-with="Saving...">Save Task diff --git a/lib/putzplan_web/live/task_live/index.ex b/lib/putzplan_web/live/task_live/index.ex index efafbbb..bf1ead8 100644 --- a/lib/putzplan_web/live/task_live/index.ex +++ b/lib/putzplan_web/live/task_live/index.ex @@ -8,7 +8,7 @@ defmodule PutzplanWeb.TaskLive.Index do Listing Tasks <:actions> <.link patch={~p"/tasks/new"}> - <.button>New Task + <.button>New Task @@ -18,21 +18,21 @@ defmodule PutzplanWeb.TaskLive.Index do rows={@streams.tasks} row_click={fn {_id, task} -> JS.navigate(~p"/tasks/#{task}") end} > + <:col :let={{_id, task}} label="Description">{task.description} - <:col :let={{_id, task}} label="Description"><%= task.description %> - - <:col :let={{_id, task}} label="Due"><%= task.due %> + <:col :let={{_id, task}} label="Due">{task.due} <:action :let={{_id, task}}>
<.link navigate={~p"/tasks/#{task}"}>Show
- - <.link patch={~p"/tasks/#{task}/edit"}>Edit - <.link phx-click={JS.push("complete", value: %{id: task.id})}>Complete - - + <:action :let={{_id, task}}> + <.link patch={~p"/tasks/#{task}/edit"}>Edit + + <:action :let={{_id, task}}> + <.link phx-click={JS.push("complete", value: %{id: task.id})}>Complete + <:action :let={{id, task}}> <.link phx-click={JS.push("delete", value: %{id: task.id}) |> hide("##{id}")} @@ -41,19 +41,19 @@ defmodule PutzplanWeb.TaskLive.Index do Delete - - <.modal :if={@live_action in [:new, :edit]} id="task-modal" show on_cancel={JS.patch(~p"/tasks")}> - <.live_component - module={PutzplanWeb.TaskLive.FormComponent} - id={(@task && @task.id) || :new} - title={@page_title} - current_user={@current_user} - action={@live_action} - task={@task} - patch={~p"/"} - /> - + + <.modal :if={@live_action in [:new, :edit]} id="task-modal" show on_cancel={JS.patch(~p"/tasks")}> + <.live_component + module={PutzplanWeb.TaskLive.FormComponent} + id={(@task && @task.id) || :new} + title={@page_title} + current_user={@current_user} + action={@live_action} + task={@task} + patch={~p"/"} + /> + """ end @@ -76,7 +76,10 @@ defmodule PutzplanWeb.TaskLive.Index do defp apply_action(socket, :edit, %{"id" => id}) do socket |> assign(:page_title, "Edit Task") - |> assign(:task, Ash.get!(Putzplan.Tasks.Task, id, actor: socket.assigns.current_user)) + |> assign( + :task, + Ash.get!(Putzplan.Tasks.Task, id, load: [:due], actor: socket.assigns.current_user) + ) end defp apply_action(socket, :new, _params) do @@ -109,7 +112,7 @@ defmodule PutzplanWeb.TaskLive.Index do 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]))} end end diff --git a/lib/putzplan_web/live/task_live/show.ex b/lib/putzplan_web/live/task_live/show.ex index 0f04a92..4124072 100644 --- a/lib/putzplan_web/live/task_live/show.ex +++ b/lib/putzplan_web/live/task_live/show.ex @@ -6,26 +6,22 @@ defmodule PutzplanWeb.TaskLive.Show do def render(assigns) do ~H""" <.header> - Task <%= @task.description %> - <:actions> - <.link patch={~p"/tasks/#{@task}/show/edit"} phx-click={JS.push_focus()}> - <.button>Edit task - - - + Task {@task.description} + <:actions> + <.link patch={~p"/tasks/#{@task}/show/edit"} phx-click={JS.push_focus()}> + <.button>Edit task + + - <.table - id="completed_tasks" - rows={@streams.completed_tasks} - > - <:col :let={{_id, completed_task}} label="Completed by"><%= completed_task.users.name %> - <:col :let={{_id, completed_task}} label="Date"><%= completed_task.completion %> - <:action :let={{id, completed_task}}> - <.link phx-click={JS.push("delete", value: %{id: completed_task.id}) |> hide("##{id}")}> - Delete - - + <.table id="completed_tasks" rows={@streams.completed_tasks}> + <:col :let={{_id, completed_task}} label="Completed by">{completed_task.users.name} + <:col :let={{_id, completed_task}} label="Date">{completed_task.completion} + <:action :let={{id, completed_task}}> + <.link phx-click={JS.push("delete", value: %{id: completed_task.id}) |> hide("##{id}")}> + Delete + + <.back navigate={~p"/"}>Back to tasks @@ -58,7 +54,9 @@ defmodule PutzplanWeb.TaskLive.Show do @impl true def handle_event("delete", %{"id" => id}, socket) do - completed_task = Ash.get!(Putzplan.Tasks.CompletedTask, id, actor: socket.assigns.current_user) + completed_task = + Ash.get!(Putzplan.Tasks.CompletedTask, id, actor: socket.assigns.current_user) + Ash.destroy!(completed_task, actor: socket.assigns.current_user) {:noreply, stream_delete(socket, :completed_tasks, completed_task)} From af1e2eb06fdda3f8c02c079b801469ddc65f10bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Mon, 7 Apr 2025 15:27:49 +0200 Subject: [PATCH 03/10] chore: remove unused stuff --- .../completed_task_live/form_component.ex | 76 ------------------ .../live/completed_task_live/index.ex | 80 ------------------- .../live/completed_task_live/show.ex | 41 ---------- lib/putzplan_web/router.ex | 4 - 4 files changed, 201 deletions(-) delete mode 100644 lib/putzplan_web/live/completed_task_live/form_component.ex delete mode 100644 lib/putzplan_web/live/completed_task_live/index.ex delete mode 100644 lib/putzplan_web/live/completed_task_live/show.ex diff --git a/lib/putzplan_web/live/completed_task_live/form_component.ex b/lib/putzplan_web/live/completed_task_live/form_component.ex deleted file mode 100644 index fc4f3ce..0000000 --- a/lib/putzplan_web/live/completed_task_live/form_component.ex +++ /dev/null @@ -1,76 +0,0 @@ -defmodule PutzplanWeb.CompletedTaskLive.FormComponent do - use PutzplanWeb, :live_component - - @impl true - def render(assigns) do - ~H""" -
- <.header> - {@title} - <:subtitle>Use this form to manage completed_task records in your database. - - - <.simple_form - for={@form} - id="completed_task-form" - phx-target={@myself} - phx-change="validate" - phx-submit="save" - > - <.input field={@form[:user]} type="text" label="User" /><.input - field={@form[:task]} - type="text" - label="Task" - /> - - <:actions> - <.button phx-disable-with="Saving...">Save Completed task - - -
- """ - end - - @impl true - def update(assigns, socket) do - {:ok, - socket - |> assign(assigns) - |> assign_form()} - end - - @impl true - def handle_event("validate", %{"completed_task" => completed_task_params}, socket) do - {:noreply, - assign(socket, form: AshPhoenix.Form.validate(socket.assigns.form, completed_task_params))} - end - - def handle_event("save", %{"completed_task" => completed_task_params}, socket) do - case AshPhoenix.Form.submit(socket.assigns.form, params: completed_task_params) do - {:ok, completed_task} -> - notify_parent({:saved, completed_task}) - - socket = - socket - |> put_flash(:info, "Completed task created successfully") - |> push_patch(to: socket.assigns.patch) - - {:noreply, socket} - - {:error, form} -> - {:noreply, assign(socket, form: form)} - end - end - - defp notify_parent(msg), do: send(self(), {__MODULE__, msg}) - - defp assign_form(%{assigns: %{completed_task: completed_task}} = socket) do - form = - AshPhoenix.Form.for_create(completed_task, :create, - as: "completed_task", - actor: socket.assigns.current_user - ) - - assign(socket, form: to_form(form)) - end -end diff --git a/lib/putzplan_web/live/completed_task_live/index.ex b/lib/putzplan_web/live/completed_task_live/index.ex deleted file mode 100644 index 0db23d7..0000000 --- a/lib/putzplan_web/live/completed_task_live/index.ex +++ /dev/null @@ -1,80 +0,0 @@ -defmodule PutzplanWeb.CompletedTaskLive.Index do - use PutzplanWeb, :live_view - - @impl true - def render(assigns) do - ~H""" - <.header> - Listing Completed tasks - <:actions> - <.link patch={~p"/completed_tasks/new"}> - <.button>New Completed task - - - - - <.table - id="completed_tasks" - rows={@streams.completed_tasks} - row_click={fn {_id, completed_task} -> JS.navigate(~p"/completed_tasks/#{completed_task}") end} - > - <:col :let={{_id, completed_task}} label="Id">{completed_task.id} - - <:action :let={{_id, completed_task}}> -
- <.link navigate={~p"/completed_tasks/#{completed_task}"}>Show -
- - - - <.modal - :if={@live_action == :new} - id="completed_task-modal" - show - on_cancel={JS.patch(~p"/completed_tasks")} - > - <.live_component - module={PutzplanWeb.CompletedTaskLive.FormComponent} - current_user={@current_user} - id={:new} - title={@page_title} - action={@live_action} - completed_task={@completed_task} - patch={~p"/completed_tasks"} - /> - - """ - end - - @impl true - def mount(_params, _session, socket) do - {:ok, - socket - |> stream( - :completed_tasks, - Ash.read!(Putzplan.Tasks.CompletedTask, actor: socket.assigns[:current_user]) - ) - |> assign_new(:current_user, fn -> nil end)} - end - - @impl true - def handle_params(params, _url, socket) do - {:noreply, apply_action(socket, socket.assigns.live_action, params)} - end - - defp apply_action(socket, :new, _params) do - socket - |> assign(:page_title, "New Completed task") - end - - defp apply_action(socket, :index, _params) do - socket - |> assign(:page_title, "Listing Completed tasks") - |> assign(:completed_task, nil) - end - - @impl true - def handle_info({PutzplanWeb.CompletedTaskLive.FormComponent, {:saved, completed_task}}, socket) do - {:noreply, stream_insert(socket, :completed_tasks, completed_task)} - end -end diff --git a/lib/putzplan_web/live/completed_task_live/show.ex b/lib/putzplan_web/live/completed_task_live/show.ex deleted file mode 100644 index f8aa0d5..0000000 --- a/lib/putzplan_web/live/completed_task_live/show.ex +++ /dev/null @@ -1,41 +0,0 @@ -defmodule PutzplanWeb.CompletedTaskLive.Show do - use PutzplanWeb, :live_view - - @impl true - def render(assigns) do - ~H""" - <.header> - Completed task {@completed_task.id} - <:subtitle>This is a completed_task record from your database. - - - <.list> - <:item title="Id">{@completed_task.id} - - - <.back navigate={~p"/completed_tasks"}>Back to completed_tasks - """ - end - - @impl true - def mount(_params, _session, socket) do - {:ok, socket} - end - - @impl true - def handle_params(%{"id" => id}, _, socket) do - actor = socket.assigns.current_user - completed_task = Ash.get!(Putzplan.Tasks.CompletedTask, id, actor: actor) - - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign( - :completed_task, - completed_task - )} - end - - defp page_title(:show), do: "Show Completed task" - defp page_title(:edit), do: "Edit Completed task" -end diff --git a/lib/putzplan_web/router.ex b/lib/putzplan_web/router.ex index 48038a7..0d17f83 100644 --- a/lib/putzplan_web/router.ex +++ b/lib/putzplan_web/router.ex @@ -45,10 +45,6 @@ defmodule PutzplanWeb.Router do live "/tasks/:id", TaskLive.Show, :show live "/tasks/:id/show/edit", TaskLive.Show, :edit - - live "/completed_tasks", CompletedTaskLive.Index, :index - live "/completed_tasks/new", CompletedTaskLive.Index, :new - live "/completed_tasks/:id", CompletedTaskLive.Show, :show end end From a59ad17743e9fa844a23e275a0f1376f4950fa23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Mon, 7 Apr 2025 15:28:11 +0200 Subject: [PATCH 04/10] feat: display due date better --- lib/putzplan_web/live/task_live/index.ex | 35 +++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/putzplan_web/live/task_live/index.ex b/lib/putzplan_web/live/task_live/index.ex index bf1ead8..579cb42 100644 --- a/lib/putzplan_web/live/task_live/index.ex +++ b/lib/putzplan_web/live/task_live/index.ex @@ -20,7 +20,7 @@ defmodule PutzplanWeb.TaskLive.Index do > <:col :let={{_id, task}} label="Description">{task.description} - <:col :let={{_id, task}} label="Due">{task.due} + <:col :let={{_id, task}} label="Due">{format_date(task.due)} <:action :let={{_id, task}}>
@@ -115,4 +115,37 @@ defmodule PutzplanWeb.TaskLive.Index do {:noreply, stream_insert(socket, :tasks, Ash.get!(Putzplan.Tasks.Task, id, load: [:due]))} end + + defp format_date(date) do + string = + case Date.diff(date, Date.utc_today()) do + 0 -> + "today" + + 1 -> + "tomorrow" + + days when days > 0 and days < 7 -> + "next " <> get_weekday(Date.day_of_week(date)) + + _ -> + Date.to_string(date) + end + + String.capitalize(string) + end + + defp get_weekday(index) do + days = %{ + 1 => "monday", + 2 => "tuesday", + 3 => "wednesday", + 4 => "thursday", + 5 => "friday", + 6 => "saturday", + 7 => "sunday" + } + + Map.get(days, index) + end end From 0b189b22834ad83d5fd6dcf4670a42990decadbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Mon, 7 Apr 2025 15:28:28 +0200 Subject: [PATCH 05/10] fix: show due today if never completed --- lib/putzplan/tasks/task.ex | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/putzplan/tasks/task.ex b/lib/putzplan/tasks/task.ex index 0e7c35d..61bfc6c 100644 --- a/lib/putzplan/tasks/task.ex +++ b/lib/putzplan/tasks/task.ex @@ -41,21 +41,25 @@ defmodule Putzplan.Tasks.Task do fragment( "SELECT c.completion FROM \"completed_tasks\" AS c WHERE c.task_id = ? ORDER BY c.completion DESC LIMIT 1", id - ) || today() + ) ) calculate :due, :date, expr( - fragment( - # HACK: to cast to date - "SELECT strftime('%F', ?)", - date_add( - last_completed, - repetition_days, - :day + if last_completed do + fragment( + # HACK: to cast to date + "SELECT strftime('%F', ?)", + date_add( + last_completed, + repetition_days, + :day + ) ) - ) + else + today() + end ) end end From b35bac062abca70ae37fb83b2da912dd3e8e1c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Mon, 7 Apr 2025 16:07:21 +0200 Subject: [PATCH 06/10] feat: somewhat useable ui --- lib/putzplan_web/live/task_live/index.ex | 70 +++++++++++++++++++----- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/lib/putzplan_web/live/task_live/index.ex b/lib/putzplan_web/live/task_live/index.ex index 579cb42..6ea1d09 100644 --- a/lib/putzplan_web/live/task_live/index.ex +++ b/lib/putzplan_web/live/task_live/index.ex @@ -18,6 +18,21 @@ defmodule PutzplanWeb.TaskLive.Index do rows={@streams.tasks} row_click={fn {_id, task} -> JS.navigate(~p"/tasks/#{task}") end} > + <:col :let={{id, task}}> + <.link phx-click={JS.push("complete", value: %{id: task.id})}> + + + + + + <:col :let={{_id, task}} label="Description">{task.description} <:col :let={{_id, task}} label="Due">{format_date(task.due)} @@ -27,20 +42,47 @@ defmodule PutzplanWeb.TaskLive.Index do <.link navigate={~p"/tasks/#{task}"}>Show
- <:action :let={{_id, task}}> - <.link patch={~p"/tasks/#{task}/edit"}>Edit - - <:action :let={{_id, task}}> - <.link phx-click={JS.push("complete", value: %{id: task.id})}>Complete - - <:action :let={{id, task}}> - <.link - phx-click={JS.push("delete", value: %{id: task.id}) |> hide("##{id}")} - data-confirm="Are you sure?" - > - Delete - - + + <:col :let={{id, task}}> + <.link patch={~p"/tasks/#{task}/edit"}> + + + + + + + <:col :let={{id, task}}> + <.link + phx-click={JS.push("delete", value: %{id: task.id}) |> hide("##{id}")} + data-confirm="Are you sure?" + > + + + + + <.modal :if={@live_action in [:new, :edit]} id="task-modal" show on_cancel={JS.patch(~p"/tasks")}> From bc27b56607dc59fdd6468940e65c959ebc747168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Mon, 7 Apr 2025 16:20:33 +0200 Subject: [PATCH 07/10] feat: make index pretty --- lib/putzplan_web/live/task_live/index.ex | 149 +++++++++++++---------- 1 file changed, 82 insertions(+), 67 deletions(-) diff --git a/lib/putzplan_web/live/task_live/index.ex b/lib/putzplan_web/live/task_live/index.ex index 6ea1d09..418a1f1 100644 --- a/lib/putzplan_web/live/task_live/index.ex +++ b/lib/putzplan_web/live/task_live/index.ex @@ -13,77 +13,92 @@ defmodule PutzplanWeb.TaskLive.Index do - <.table - id="tasks" - rows={@streams.tasks} - row_click={fn {_id, task} -> JS.navigate(~p"/tasks/#{task}") end} - > - <:col :let={{id, task}}> - <.link phx-click={JS.push("complete", value: %{id: task.id})}> - - - - - +
+ <%= for {id, task} <- @streams.tasks do %> +
+
+
{task.description}
+
+ <.link + phx-click={JS.push("complete", value: %{id: task.id})} + class="text-green-600 hover:text-green-800 p-1 rounded-full hover:bg-green-100" + > + + + + +
+
- <:col :let={{_id, task}} label="Description">{task.description} +
+
Due
+
{format_date(task.due)}
+
- <:col :let={{_id, task}} label="Due">{format_date(task.due)} +
+
+ <.link navigate={~p"/tasks/#{task}"}>Show +
- <:action :let={{_id, task}}> -
- <.link navigate={~p"/tasks/#{task}"}>Show +
+ <.link + patch={~p"/tasks/#{task}/edit"} + class="text-blue-600 hover:text-blue-800 p-1 rounded-full hover:bg-blue-100" + phx-click-stop-propagation="true" + > + + + + + + <.link + phx-click={JS.push("delete", value: %{id: task.id}) |> hide("#task-#{id}")} + data-confirm="Are you sure?" + class="text-red-600 hover:text-red-800 p-1 rounded-full hover:bg-red-100" + phx-click-stop-propagation="true" + > + + + + +
+
- - - <:col :let={{id, task}}> - <.link patch={~p"/tasks/#{task}/edit"}> - - - - - - - <:col :let={{id, task}}> - <.link - phx-click={JS.push("delete", value: %{id: task.id}) |> hide("##{id}")} - data-confirm="Are you sure?" - > - - - - - - + <% end %> +
<.modal :if={@live_action in [:new, :edit]} id="task-modal" show on_cancel={JS.patch(~p"/tasks")}> <.live_component From e72f6f29c12ab8771c9fb46c54f6b2f8a2eec9b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Mon, 7 Apr 2025 16:55:26 +0200 Subject: [PATCH 08/10] feat: prettify history --- lib/putzplan_web/live/task_live/show.ex | 79 ++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/lib/putzplan_web/live/task_live/show.ex b/lib/putzplan_web/live/task_live/show.ex index 4124072..7c24b73 100644 --- a/lib/putzplan_web/live/task_live/show.ex +++ b/lib/putzplan_web/live/task_live/show.ex @@ -14,15 +14,76 @@ defmodule PutzplanWeb.TaskLive.Show do - <.table id="completed_tasks" rows={@streams.completed_tasks}> - <:col :let={{_id, completed_task}} label="Completed by">{completed_task.users.name} - <:col :let={{_id, completed_task}} label="Date">{completed_task.completion} - <:action :let={{id, completed_task}}> - <.link phx-click={JS.push("delete", value: %{id: completed_task.id}) |> hide("##{id}")}> - Delete - - - +
+
    +
  • +
    +
    Completed by
    +
    + + {String.first(completed_task.users.name)} + + {completed_task.users.name} +
    +
    + +
    +
    Date
    +
    {completed_task.completion}
    +
    + +
    + <.link + phx-click={ + JS.push("delete", value: %{id: completed_task.id}) |> hide("#completed-task-#{id}") + } + class="text-sm text-red-600 hover:text-red-800 flex items-center" + > + + + + Delete + +
    +
  • + + +
+
+ + <.modal + :if={@live_action in [:new, :edit]} + id="task-modal" + show + on_cancel={JS.patch(~p"/tasks/#{@task}")} + > + <.live_component + module={PutzplanWeb.TaskLive.FormComponent} + id={(@task && @task.id) || :new} + title={@page_title} + current_user={@current_user} + action={@live_action} + task={@task} + patch={~p"/"} + /> + <.back navigate={~p"/"}>Back to tasks """ From 8de0f1e39f19dc75fd400c9d8856960b32248afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Tue, 8 Apr 2025 11:58:37 +0200 Subject: [PATCH 09/10] feat: use pubsub to sync states --- .../live/task_live/form_component.ex | 8 +-- lib/putzplan_web/live/task_live/index.ex | 51 +++++++++++++++---- lib/putzplan_web/live/task_live/show.ex | 22 +++++++- 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/lib/putzplan_web/live/task_live/form_component.ex b/lib/putzplan_web/live/task_live/form_component.ex index c0e212d..38cf74f 100644 --- a/lib/putzplan_web/live/task_live/form_component.ex +++ b/lib/putzplan_web/live/task_live/form_component.ex @@ -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 diff --git a/lib/putzplan_web/live/task_live/index.ex b/lib/putzplan_web/live/task_live/index.ex index 418a1f1..fbf9907 100644 --- a/lib/putzplan_web/live/task_live/index.ex +++ b/lib/putzplan_web/live/task_live/index.ex @@ -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" diff --git a/lib/putzplan_web/live/task_live/show.ex b/lib/putzplan_web/live/task_live/show.ex index 7c24b73..daa59c2 100644 --- a/lib/putzplan_web/live/task_live/show.ex +++ b/lib/putzplan_web/live/task_live/show.ex @@ -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 From e25fc5ed64647cd37d8a808872e3d2c76c7fd31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Tue, 8 Apr 2025 12:26:57 +0200 Subject: [PATCH 10/10] refactor: add pub_sub module --- lib/putzplan/pub_sub.ex | 43 ++++++++++++++++++++++++ lib/putzplan_web/live/task_live/index.ex | 21 ++++-------- lib/putzplan_web/live/task_live/show.ex | 16 +++------ 3 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 lib/putzplan/pub_sub.ex diff --git a/lib/putzplan/pub_sub.ex b/lib/putzplan/pub_sub.ex new file mode 100644 index 0000000..d7bcbd6 --- /dev/null +++ b/lib/putzplan/pub_sub.ex @@ -0,0 +1,43 @@ +defmodule Putzplan.PubSub do + @tasks_topic "tasks" + + def subscribe_completed(id) do + Phoenix.PubSub.subscribe(__MODULE__, get_topic(id)) + end + + def subscribe_tasks do + Phoenix.PubSub.subscribe(__MODULE__, @tasks_topic) + end + + def upsert_task(task) do + Phoenix.PubSub.broadcast!(__MODULE__, @tasks_topic, {:upsert, task}) + end + + def delete_task(task) do + Phoenix.PubSub.broadcast!(__MODULE__, @tasks_topic, {:delete, task}) + end + + def update_task_by_id(id) do + Phoenix.PubSub.broadcast!(__MODULE__, @tasks_topic, {:update, id}) + end + + def upsert_completed_task(completed_task) do + Phoenix.PubSub.broadcast!( + __MODULE__, + get_topic(completed_task.tasks.id), + {:upsert, completed_task} + ) + end + + def delete_completed_task(completed_task) do + Phoenix.PubSub.broadcast!( + __MODULE__, + get_topic(completed_task.tasks.id), + {:delete, completed_task} + ) + end + + defp get_topic(id) do + "completed:" <> id + end +end diff --git a/lib/putzplan_web/live/task_live/index.ex b/lib/putzplan_web/live/task_live/index.ex index fbf9907..70cf5dc 100644 --- a/lib/putzplan_web/live/task_live/index.ex +++ b/lib/putzplan_web/live/task_live/index.ex @@ -1,13 +1,6 @@ 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""" @@ -23,7 +16,7 @@ defmodule PutzplanWeb.TaskLive.Index do
<%= for {id, task} <- @streams.tasks do %>
@@ -81,7 +74,7 @@ defmodule PutzplanWeb.TaskLive.Index do <.link - phx-click={JS.push("delete", value: %{id: task.id}) |> hide("#task-#{id}")} + phx-click={JS.push("delete", value: %{id: task.id}) |> hide(id)} data-confirm="Are you sure?" class="text-red-600 hover:text-red-800 p-1 rounded-full hover:bg-red-100" phx-click-stop-propagation="true" @@ -123,7 +116,7 @@ defmodule PutzplanWeb.TaskLive.Index do @impl true def mount(_params, _session, socket) do - if connected?(socket), do: Phoenix.PubSub.subscribe(@pubsub_name, @pubsub_topic) + if connected?(socket), do: Putzplan.PubSub.subscribe_tasks() {:ok, socket @@ -180,9 +173,9 @@ defmodule PutzplanWeb.TaskLive.Index do 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}) + Putzplan.PubSub.delete_task(task) - {:noreply, task} + {:noreply, socket} end @impl true @@ -193,8 +186,8 @@ defmodule PutzplanWeb.TaskLive.Index do |> Ash.create!(actor: socket.assigns.current_user) 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}) + Putzplan.PubSub.upsert_task(task) + Putzplan.PubSub.upsert_completed_task(completed_task) {:noreply, socket} end diff --git a/lib/putzplan_web/live/task_live/show.ex b/lib/putzplan_web/live/task_live/show.ex index daa59c2..68d0f2f 100644 --- a/lib/putzplan_web/live/task_live/show.ex +++ b/lib/putzplan_web/live/task_live/show.ex @@ -2,17 +2,11 @@ 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""" <.header> - Task {@task.description} + {@task.description} <:actions> <.link patch={~p"/tasks/#{@task}/show/edit"} phx-click={JS.push_focus()}> <.button>Edit task @@ -87,7 +81,7 @@ defmodule PutzplanWeb.TaskLive.Show do current_user={@current_user} action={@live_action} task={@task} - patch={~p"/"} + patch={~p"/tasks/#{@task}"} /> @@ -97,7 +91,7 @@ defmodule PutzplanWeb.TaskLive.Show do @impl true def mount(%{"id" => id}, _session, socket) do - if connected?(socket), do: Phoenix.PubSub.subscribe(@pubsub_name, get_topic(id)) + if connected?(socket), do: Putzplan.PubSub.subscribe_completed(id) {:ok, socket} end @@ -127,8 +121,8 @@ 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}) + Putzplan.PubSub.delete_completed_task(completed_task) + Putzplan.PubSub.update_task_by_id(completed_task.tasks.id) {:noreply, socket} end