diff options
Diffstat (limited to 'lib/aggiedit_web/live')
-rw-r--r-- | lib/aggiedit_web/live/live_helpers.ex | 60 | ||||
-rw-r--r-- | lib/aggiedit_web/live/post_live/form_component.ex | 55 | ||||
-rw-r--r-- | lib/aggiedit_web/live/post_live/form_component.html.heex | 24 | ||||
-rw-r--r-- | lib/aggiedit_web/live/post_live/index.ex | 46 | ||||
-rw-r--r-- | lib/aggiedit_web/live/post_live/index.html.heex | 41 | ||||
-rw-r--r-- | lib/aggiedit_web/live/post_live/show.ex | 21 | ||||
-rw-r--r-- | lib/aggiedit_web/live/post_live/show.html.heex | 31 |
7 files changed, 278 insertions, 0 deletions
diff --git a/lib/aggiedit_web/live/live_helpers.ex b/lib/aggiedit_web/live/live_helpers.ex new file mode 100644 index 0000000..aa6b28a --- /dev/null +++ b/lib/aggiedit_web/live/live_helpers.ex @@ -0,0 +1,60 @@ +defmodule AggieditWeb.LiveHelpers do + import Phoenix.LiveView + import Phoenix.LiveView.Helpers + + alias Phoenix.LiveView.JS + + @doc """ + Renders a live component inside a modal. + + The rendered modal receives a `:return_to` option to properly update + the URL when the modal is closed. + + ## Examples + + <.modal return_to={Routes.post_index_path(@socket, :index)}> + <.live_component + module={AggieditWeb.PostLive.FormComponent} + id={@post.id || :new} + title={@page_title} + action={@live_action} + return_to={Routes.post_index_path(@socket, :index)} + post: @post + /> + </.modal> + """ + def modal(assigns) do + assigns = assign_new(assigns, :return_to, fn -> nil end) + + ~H""" + <div id="modal" class="phx-modal fade-in" phx-remove={hide_modal()}> + <div + id="modal-content" + class="phx-modal-content fade-in-scale" + phx-click-away={JS.dispatch("click", to: "#close")} + phx-window-keydown={JS.dispatch("click", to: "#close")} + phx-key="escape" + > + <%= if @return_to do %> + <%= live_patch "✖", + to: @return_to, + id: "close", + class: "phx-modal-close", + phx_click: hide_modal() + %> + <% else %> + <a id="close" href="#" class="phx-modal-close" phx-click={hide_modal()}>✖</a> + <% end %> + + <%= render_slot(@inner_block) %> + </div> + </div> + """ + end + + defp hide_modal(js \\ %JS{}) do + js + |> JS.hide(to: "#modal", transition: "fade-out") + |> JS.hide(to: "#modal-content", transition: "fade-out-scale") + end +end diff --git a/lib/aggiedit_web/live/post_live/form_component.ex b/lib/aggiedit_web/live/post_live/form_component.ex new file mode 100644 index 0000000..11ad4a1 --- /dev/null +++ b/lib/aggiedit_web/live/post_live/form_component.ex @@ -0,0 +1,55 @@ +defmodule AggieditWeb.PostLive.FormComponent do + use AggieditWeb, :live_component + + alias Aggiedit.Rooms + + @impl true + def update(%{post: post} = assigns, socket) do + changeset = Rooms.change_post(post) + + {:ok, + socket + |> assign(assigns) + |> assign(:changeset, changeset)} + end + + @impl true + def handle_event("validate", %{"post" => post_params}, socket) do + changeset = + socket.assigns.post + |> Rooms.change_post(post_params) + |> Map.put(:action, :validate) + + {:noreply, assign(socket, :changeset, changeset)} + end + + def handle_event("save", %{"post" => post_params}, socket) do + save_post(socket, socket.assigns.action, post_params) + end + + defp save_post(socket, :edit, post_params) do + case Rooms.update_post(socket.assigns.post, post_params) do + {:ok, _post} -> + {:noreply, + socket + |> put_flash(:info, "Post updated successfully") + |> push_redirect(to: socket.assigns.return_to)} + + {:error, %Ecto.Changeset{} = changeset} -> + {:noreply, assign(socket, :changeset, changeset)} + end + end + + defp save_post(socket, :new, post_params) do + case Rooms.create_post(post_params) do + {:ok, _post} -> + {:noreply, + socket + |> put_flash(:info, "Post created successfully") + |> push_redirect(to: socket.assigns.return_to)} + + {:error, %Ecto.Changeset{} = changeset} -> + {:noreply, assign(socket, changeset: changeset)} + end + end +end diff --git a/lib/aggiedit_web/live/post_live/form_component.html.heex b/lib/aggiedit_web/live/post_live/form_component.html.heex new file mode 100644 index 0000000..682ec78 --- /dev/null +++ b/lib/aggiedit_web/live/post_live/form_component.html.heex @@ -0,0 +1,24 @@ +<div> + <h2><%= @title %></h2> + + <.form + let={f} + for={@changeset} + id="post-form" + phx-target={@myself} + phx-change="validate" + phx-submit="save"> + + <%= label f, :title %> + <%= textarea f, :title %> + <%= error_tag f, :title %> + + <%= label f, :body %> + <%= textarea f, :body %> + <%= error_tag f, :body %> + + <div> + <%= submit "Save", phx_disable_with: "Saving..." %> + </div> + </.form> +</div> diff --git a/lib/aggiedit_web/live/post_live/index.ex b/lib/aggiedit_web/live/post_live/index.ex new file mode 100644 index 0000000..0b12ed0 --- /dev/null +++ b/lib/aggiedit_web/live/post_live/index.ex @@ -0,0 +1,46 @@ +defmodule AggieditWeb.PostLive.Index do + use AggieditWeb, :live_view + + alias Aggiedit.Rooms + alias Aggiedit.Rooms.Post + + @impl true + def mount(_params, _session, socket) do + {:ok, assign(socket, :posts, list_posts())} + 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 Post") + |> assign(:post, Rooms.get_post!(id)) + end + + defp apply_action(socket, :new, _params) do + socket + |> assign(:page_title, "New Post") + |> assign(:post, %Post{}) + end + + defp apply_action(socket, :index, _params) do + socket + |> assign(:page_title, "Listing Posts") + |> assign(:post, nil) + end + + @impl true + def handle_event("delete", %{"id" => id}, socket) do + post = Rooms.get_post!(id) + {:ok, _} = Rooms.delete_post(post) + + {:noreply, assign(socket, :posts, list_posts())} + end + + defp list_posts do + Rooms.list_posts() + end +end diff --git a/lib/aggiedit_web/live/post_live/index.html.heex b/lib/aggiedit_web/live/post_live/index.html.heex new file mode 100644 index 0000000..4297d5a --- /dev/null +++ b/lib/aggiedit_web/live/post_live/index.html.heex @@ -0,0 +1,41 @@ +<h1>Listing Posts</h1> + +<%= if @live_action in [:new, :edit] do %> + <.modal return_to={Routes.post_index_path(@socket, :index)}> + <.live_component + module={AggieditWeb.PostLive.FormComponent} + id={@post.id || :new} + title={@page_title} + action={@live_action} + post={@post} + return_to={Routes.post_index_path(@socket, :index)} + /> + </.modal> +<% end %> + +<table> + <thead> + <tr> + <th>Title</th> + <th>Body</th> + + <th></th> + </tr> + </thead> + <tbody id="posts"> + <%= for post <- @posts do %> + <tr id={"post-#{post.id}"}> + <td><%= post.title %></td> + <td><%= post.body %></td> + + <td> + <span><%= live_redirect "Show", to: Routes.post_show_path(@socket, :show, post) %></span> + <span><%= live_patch "Edit", to: Routes.post_index_path(@socket, :edit, post) %></span> + <span><%= link "Delete", to: "#", phx_click: "delete", phx_value_id: post.id, data: [confirm: "Are you sure?"] %></span> + </td> + </tr> + <% end %> + </tbody> +</table> + +<span><%= live_patch "New Post", to: Routes.post_index_path(@socket, :new) %></span> diff --git a/lib/aggiedit_web/live/post_live/show.ex b/lib/aggiedit_web/live/post_live/show.ex new file mode 100644 index 0000000..2416156 --- /dev/null +++ b/lib/aggiedit_web/live/post_live/show.ex @@ -0,0 +1,21 @@ +defmodule AggieditWeb.PostLive.Show do + use AggieditWeb, :live_view + + alias Aggiedit.Rooms + + @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(:post, Rooms.get_post!(id))} + end + + defp page_title(:show), do: "Show Post" + defp page_title(:edit), do: "Edit Post" +end diff --git a/lib/aggiedit_web/live/post_live/show.html.heex b/lib/aggiedit_web/live/post_live/show.html.heex new file mode 100644 index 0000000..e6eaebe --- /dev/null +++ b/lib/aggiedit_web/live/post_live/show.html.heex @@ -0,0 +1,31 @@ +<h1>Show Post</h1> + +<%= if @live_action in [:edit] do %> + <.modal return_to={Routes.post_show_path(@socket, :show, @post)}> + <.live_component + module={AggieditWeb.PostLive.FormComponent} + id={@post.id} + title={@page_title} + action={@live_action} + post={@post} + return_to={Routes.post_show_path(@socket, :show, @post)} + /> + </.modal> +<% end %> + +<ul> + + <li> + <strong>Title:</strong> + <%= @post.title %> + </li> + + <li> + <strong>Body:</strong> + <%= @post.body %> + </li> + +</ul> + +<span><%= live_patch "Edit", to: Routes.post_show_path(@socket, :edit, @post), class: "button" %></span> | +<span><%= live_redirect "Back", to: Routes.post_index_path(@socket, :index) %></span> |