From 532b209b3a6c9b60d2c6537c729280d28cf4d976 Mon Sep 17 00:00:00 2001 From: KKlochko Date: Sun, 16 Mar 2025 09:43:49 +0200 Subject: [PATCH] Add LiveViews for Publisher. --- .../live/publisher_live/form_component.ex | 83 +++++++++++++ .../live/publisher_live/index.ex | 116 ++++++++++++++++++ .../live/publisher_live/show.ex | 63 ++++++++++ lib/decentralised_book_index_web/router.ex | 7 ++ 4 files changed, 269 insertions(+) create mode 100644 lib/decentralised_book_index_web/live/publisher_live/form_component.ex create mode 100644 lib/decentralised_book_index_web/live/publisher_live/index.ex create mode 100644 lib/decentralised_book_index_web/live/publisher_live/show.ex diff --git a/lib/decentralised_book_index_web/live/publisher_live/form_component.ex b/lib/decentralised_book_index_web/live/publisher_live/form_component.ex new file mode 100644 index 0000000..a283cce --- /dev/null +++ b/lib/decentralised_book_index_web/live/publisher_live/form_component.ex @@ -0,0 +1,83 @@ +defmodule DecentralisedBookIndexWeb.PublisherLive.FormComponent do + use DecentralisedBookIndexWeb, :live_component + + @impl true + def render(assigns) do + ~H""" +
+ <.header> + {@title} + <:subtitle>Use this form to manage publisher records in your database. + + + <.simple_form + for={@form} + id="publisher-form" + phx-target={@myself} + phx-change="validate" + phx-submit="save" + > + <%= if @form.source.type == :create do %> + <.input field={@form[:name]} type="text" label="Name" /> + <% end %> + <%= if @form.source.type == :update do %> + <% end %> + + <:actions> + <.button phx-disable-with="Saving...">Save Publisher + + +
+ """ + end + + @impl true + def update(assigns, socket) do + {:ok, + socket + |> assign(assigns) + |> assign_form()} + end + + @impl true + def handle_event("validate", %{"publisher" => publisher_params}, socket) do + {:noreply, + assign(socket, form: AshPhoenix.Form.validate(socket.assigns.form, publisher_params))} + end + + def handle_event("save", %{"publisher" => publisher_params}, socket) do + case AshPhoenix.Form.submit(socket.assigns.form, params: publisher_params) do + {:ok, publisher} -> + notify_parent({:saved, publisher}) + + socket = + socket + |> put_flash(:info, "Publisher #{socket.assigns.form.source.type}d 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: %{publisher: publisher}} = socket) do + form = + if publisher do + AshPhoenix.Form.for_update(publisher, :update, + as: "publisher", + actor: socket.assigns.current_user + ) + else + AshPhoenix.Form.for_create(DecentralisedBookIndex.Metadata.Publisher, :create, + as: "publisher", + actor: socket.assigns.current_user + ) + end + + assign(socket, form: to_form(form)) + end +end diff --git a/lib/decentralised_book_index_web/live/publisher_live/index.ex b/lib/decentralised_book_index_web/live/publisher_live/index.ex new file mode 100644 index 0000000..66df2de --- /dev/null +++ b/lib/decentralised_book_index_web/live/publisher_live/index.ex @@ -0,0 +1,116 @@ +defmodule DecentralisedBookIndexWeb.PublisherLive.Index do + use DecentralisedBookIndexWeb, :live_view + + @impl true + def render(assigns) do + ~H""" + <.header> + Listing Publishers + <:actions> + <.link patch={~p"/publishers/new"}> + <.button>New Publisher + + + + + <.table + id="publishers" + rows={@streams.publishers} + row_click={fn {_id, publisher} -> JS.navigate(~p"/publishers/#{publisher}") end} + > + <:col :let={{_id, publisher}} label="Id">{publisher.id} + + <:col :let={{_id, publisher}} label="Name">{publisher.name} + + <:action :let={{_id, publisher}}> +
+ <.link navigate={~p"/publishers/#{publisher}"}>Show +
+ + <.link patch={~p"/publishers/#{publisher}/edit"}>Edit + + + <:action :let={{id, publisher}}> + <.link + phx-click={JS.push("delete", value: %{id: publisher.id}) |> hide("##{id}")} + data-confirm="Are you sure?" + > + Delete + + + + + <.modal + :if={@live_action in [:new, :edit]} + id="publisher-modal" + show + on_cancel={JS.patch(~p"/publishers")} + > + <.live_component + module={DecentralisedBookIndexWeb.PublisherLive.FormComponent} + id={(@publisher && @publisher.id) || :new} + title={@page_title} + current_user={@current_user} + action={@live_action} + publisher={@publisher} + patch={~p"/publishers"} + /> + + """ + end + + @impl true + def mount(_params, _session, socket) do + {:ok, + socket + |> stream( + :publishers, + Ash.read!(DecentralisedBookIndex.Metadata.Publisher, 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, :edit, %{"id" => id}) do + socket + |> assign(:page_title, "Edit Publisher") + |> assign( + :publisher, + Ash.get!(DecentralisedBookIndex.Metadata.Publisher, id, actor: socket.assigns.current_user) + ) + end + + defp apply_action(socket, :new, _params) do + socket + |> assign(:page_title, "New Publisher") + |> assign(:publisher, nil) + end + + defp apply_action(socket, :index, _params) do + socket + |> assign(:page_title, "Listing Publishers") + |> assign(:publisher, nil) + end + + @impl true + def handle_info( + {DecentralisedBookIndexWeb.PublisherLive.FormComponent, {:saved, publisher}}, + socket + ) do + {:noreply, stream_insert(socket, :publishers, publisher)} + end + + @impl true + def handle_event("delete", %{"id" => id}, socket) do + publisher = + Ash.get!(DecentralisedBookIndex.Metadata.Publisher, id, actor: socket.assigns.current_user) + + Ash.destroy!(publisher, actor: socket.assigns.current_user) + + {:noreply, stream_delete(socket, :publishers, publisher)} + end +end diff --git a/lib/decentralised_book_index_web/live/publisher_live/show.ex b/lib/decentralised_book_index_web/live/publisher_live/show.ex new file mode 100644 index 0000000..abf4dcb --- /dev/null +++ b/lib/decentralised_book_index_web/live/publisher_live/show.ex @@ -0,0 +1,63 @@ +defmodule DecentralisedBookIndexWeb.PublisherLive.Show do + use DecentralisedBookIndexWeb, :live_view + + @impl true + def render(assigns) do + ~H""" + <.header> + Publisher {@publisher.id} + <:subtitle>This is a publisher record from your database. + + <:actions> + <.link patch={~p"/publishers/#{@publisher}/show/edit"} phx-click={JS.push_focus()}> + <.button>Edit publisher + + + + + <.list> + <:item title="Id">{@publisher.id} + + <:item title="Name">{@publisher.name} + + + <.back navigate={~p"/publishers"}>Back to publishers + + <.modal + :if={@live_action == :edit} + id="publisher-modal" + show + on_cancel={JS.patch(~p"/publishers/#{@publisher}")} + > + <.live_component + module={DecentralisedBookIndexWeb.PublisherLive.FormComponent} + id={@publisher.id} + title={@page_title} + action={@live_action} + current_user={@current_user} + publisher={@publisher} + patch={~p"/publishers/#{@publisher}"} + /> + + """ + end + + @impl true + def mount(_params, _session, socket) do + {:ok, socket} + end + + @impl true + def handle_params(%{"id" => id}, _, socket) do + {:noreply, + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign( + :publisher, + Ash.get!(DecentralisedBookIndex.Metadata.Publisher, id, actor: socket.assigns.current_user) + )} + end + + defp page_title(:show), do: "Show Publisher" + defp page_title(:edit), do: "Edit Publisher" +end diff --git a/lib/decentralised_book_index_web/router.ex b/lib/decentralised_book_index_web/router.ex index 07a610d..dcd79c8 100644 --- a/lib/decentralised_book_index_web/router.ex +++ b/lib/decentralised_book_index_web/router.ex @@ -42,6 +42,13 @@ defmodule DecentralisedBookIndexWeb.Router do live "/authors/:id", AuthorLive.Show, :show live "/authors/:id/show/edit", AuthorLive.Show, :edit + live "/publishers", PublisherLive.Index, :index + live "/publishers/new", PublisherLive.Index, :new + live "/publishers/:id/edit", PublisherLive.Index, :edit + + live "/publishers/:id", PublisherLive.Show, :show + live "/publishers/:id/show/edit", PublisherLive.Show, :edit + ash_authentication_live_session :authenticated_routes do # in each liveview, add one of the following at the top of the module: #