Browse Source

feat: add lists

main
Inhji Y. 8 months ago
parent
commit
f62368bb3a
  1. 104
      lib/mirage/lists.ex
  2. 18
      lib/mirage/lists/list.ex
  3. 55
      lib/mirage_web/live/list_live/form_component.ex
  4. 18
      lib/mirage_web/live/list_live/form_component.html.leex
  5. 46
      lib/mirage_web/live/list_live/index.ex
  6. 37
      lib/mirage_web/live/list_live/index.html.leex
  7. 21
      lib/mirage_web/live/list_live/show.ex
  8. 27
      lib/mirage_web/live/list_live/show.html.leex
  9. 13
      priv/repo/migrations/20210227074240_create_lists.exs
  10. 66
      test/mirage/lists_test.exs
  11. 116
      test/mirage_web/live/list_live_test.exs

104
lib/mirage/lists.ex

@ -0,0 +1,104 @@
defmodule Mirage.Lists do
@moduledoc """
The Lists context.
"""
import Ecto.Query, warn: false
alias Mirage.Repo
alias Mirage.Lists.List
@doc """
Returns the list of lists.
## Examples
iex> list_lists()
[%List{}, ...]
"""
def list_lists do
Repo.all(List)
end
@doc """
Gets a single list.
Raises `Ecto.NoResultsError` if the List does not exist.
## Examples
iex> get_list!(123)
%List{}
iex> get_list!(456)
** (Ecto.NoResultsError)
"""
def get_list!(id), do: Repo.get!(List, id)
@doc """
Creates a list.
## Examples
iex> create_list(%{field: value})
{:ok, %List{}}
iex> create_list(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_list(attrs \\ %{}) do
%List{}
|> List.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a list.
## Examples
iex> update_list(list, %{field: new_value})
{:ok, %List{}}
iex> update_list(list, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_list(%List{} = list, attrs) do
list
|> List.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a list.
## Examples
iex> delete_list(list)
{:ok, %List{}}
iex> delete_list(list)
{:error, %Ecto.Changeset{}}
"""
def delete_list(%List{} = list) do
Repo.delete(list)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking list changes.
## Examples
iex> change_list(list)
%Ecto.Changeset{data: %List{}}
"""
def change_list(%List{} = list, attrs \\ %{}) do
List.changeset(list, attrs)
end
end

18
lib/mirage/lists/list.ex

@ -0,0 +1,18 @@
defmodule Mirage.Lists.List do
use Ecto.Schema
import Ecto.Changeset
schema "lists" do
field :is_public, :boolean, default: false
field :name, :string
timestamps()
end
@doc false
def changeset(list, attrs) do
list
|> cast(attrs, [:name, :is_public])
|> validate_required([:name, :is_public])
end
end

55
lib/mirage_web/live/list_live/form_component.ex

@ -0,0 +1,55 @@
defmodule MirageWeb.ListLive.FormComponent do
use MirageWeb, :live_component
alias Mirage.Lists
@impl true
def update(%{list: list} = assigns, socket) do
changeset = Lists.change_list(list)
{:ok,
socket
|> assign(assigns)
|> assign(:changeset, changeset)}
end
@impl true
def handle_event("validate", %{"list" => list_params}, socket) do
changeset =
socket.assigns.list
|> Lists.change_list(list_params)
|> Map.put(:action, :validate)
{:noreply, assign(socket, :changeset, changeset)}
end
def handle_event("save", %{"list" => list_params}, socket) do
save_list(socket, socket.assigns.action, list_params)
end
defp save_list(socket, :edit, list_params) do
case Lists.update_list(socket.assigns.list, list_params) do
{:ok, _list} ->
{:noreply,
socket
|> put_flash(:info, "List updated successfully")
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :changeset, changeset)}
end
end
defp save_list(socket, :new, list_params) do
case Lists.create_list(list_params) do
{:ok, _list} ->
{:noreply,
socket
|> put_flash(:info, "List created successfully")
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, changeset: changeset)}
end
end
end

18
lib/mirage_web/live/list_live/form_component.html.leex

@ -0,0 +1,18 @@
<h2><%= @title %></h2>
<%= f = form_for @changeset, "#",
id: "list-form",
phx_target: @myself,
phx_change: "validate",
phx_submit: "save" %>
<%= label f, :name %>
<%= text_input f, :name %>
<%= error_tag f, :name %>
<%= label f, :is_public %>
<%= checkbox f, :is_public %>
<%= error_tag f, :is_public %>
<%= submit "Save", phx_disable_with: "Saving..." %>
</form>

46
lib/mirage_web/live/list_live/index.ex

@ -0,0 +1,46 @@
defmodule MirageWeb.ListLive.Index do
use MirageWeb, :live_view
alias Mirage.Lists
alias Mirage.Lists.List
@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, :lists, list_lists())}
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 List")
|> assign(:list, Lists.get_list!(id))
end
defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New List")
|> assign(:list, %List{})
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, "Listing Lists")
|> assign(:list, nil)
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
list = Lists.get_list!(id)
{:ok, _} = Lists.delete_list(list)
{:noreply, assign(socket, :lists, list_lists())}
end
defp list_lists do
Lists.list_lists()
end
end

37
lib/mirage_web/live/list_live/index.html.leex

@ -0,0 +1,37 @@
<h1>Listing Lists</h1>
<%= if @live_action in [:new, :edit] do %>
<%= live_modal @socket, MirageWeb.ListLive.FormComponent,
id: @list.id || :new,
title: @page_title,
action: @live_action,
list: @list,
return_to: Routes.list_index_path(@socket, :index) %>
<% end %>
<table>
<thead>
<tr>
<th>Name</th>
<th>Is public</th>
<th></th>
</tr>
</thead>
<tbody id="lists">
<%= for list <- @lists do %>
<tr id="list-<%= list.id %>">
<td><%= list.name %></td>
<td><%= list.is_public %></td>
<td>
<span><%= live_redirect "Show", to: Routes.list_show_path(@socket, :show, list) %></span>
<span><%= live_patch "Edit", to: Routes.list_index_path(@socket, :edit, list) %></span>
<span><%= link "Delete", to: "#", phx_click: "delete", phx_value_id: list.id, data: [confirm: "Are you sure?"] %></span>
</td>
</tr>
<% end %>
</tbody>
</table>
<span><%= live_patch "New List", to: Routes.list_index_path(@socket, :new) %></span>

21
lib/mirage_web/live/list_live/show.ex

@ -0,0 +1,21 @@
defmodule MirageWeb.ListLive.Show do
use MirageWeb, :live_view
alias Mirage.Lists
@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(:list, Lists.get_list!(id))}
end
defp page_title(:show), do: "Show List"
defp page_title(:edit), do: "Edit List"
end

27
lib/mirage_web/live/list_live/show.html.leex

@ -0,0 +1,27 @@
<h1>Show List</h1>
<%= if @live_action in [:edit] do %>
<%= live_modal @socket, MirageWeb.ListLive.FormComponent,
id: @list.id,
title: @page_title,
action: @live_action,
list: @list,
return_to: Routes.list_show_path(@socket, :show, @list) %>
<% end %>
<ul>
<li>
<strong>Name:</strong>
<%= @list.name %>
</li>
<li>
<strong>Is public:</strong>
<%= @list.is_public %>
</li>
</ul>
<span><%= live_patch "Edit", to: Routes.list_show_path(@socket, :edit, @list), class: "button" %></span>
<span><%= live_redirect "Back", to: Routes.list_index_path(@socket, :index) %></span>

13
priv/repo/migrations/20210227074240_create_lists.exs

@ -0,0 +1,13 @@
defmodule Mirage.Repo.Migrations.CreateLists do
use Ecto.Migration
def change do
create table(:lists) do
add :name, :string
add :is_public, :boolean, default: false, null: false
timestamps()
end
end
end

66
test/mirage/lists_test.exs

@ -0,0 +1,66 @@
defmodule Mirage.ListsTest do
use Mirage.DataCase
alias Mirage.Lists
describe "lists" do
alias Mirage.Lists.List
@valid_attrs %{is_public: true, name: "some name"}
@update_attrs %{is_public: false, name: "some updated name"}
@invalid_attrs %{is_public: nil, name: nil}
def list_fixture(attrs \\ %{}) do
{:ok, list} =
attrs
|> Enum.into(@valid_attrs)
|> Lists.create_list()
list
end
test "list_lists/0 returns all lists" do
list = list_fixture()
assert Lists.list_lists() == [list]
end
test "get_list!/1 returns the list with given id" do
list = list_fixture()
assert Lists.get_list!(list.id) == list
end
test "create_list/1 with valid data creates a list" do
assert {:ok, %List{} = list} = Lists.create_list(@valid_attrs)
assert list.is_public == true
assert list.name == "some name"
end
test "create_list/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Lists.create_list(@invalid_attrs)
end
test "update_list/2 with valid data updates the list" do
list = list_fixture()
assert {:ok, %List{} = list} = Lists.update_list(list, @update_attrs)
assert list.is_public == false
assert list.name == "some updated name"
end
test "update_list/2 with invalid data returns error changeset" do
list = list_fixture()
assert {:error, %Ecto.Changeset{}} = Lists.update_list(list, @invalid_attrs)
assert list == Lists.get_list!(list.id)
end
test "delete_list/1 deletes the list" do
list = list_fixture()
assert {:ok, %List{}} = Lists.delete_list(list)
assert_raise Ecto.NoResultsError, fn -> Lists.get_list!(list.id) end
end
test "change_list/1 returns a list changeset" do
list = list_fixture()
assert %Ecto.Changeset{} = Lists.change_list(list)
end
end
end

116
test/mirage_web/live/list_live_test.exs

@ -0,0 +1,116 @@
defmodule MirageWeb.ListLiveTest do
use MirageWeb.ConnCase
import Phoenix.LiveViewTest
alias Mirage.Lists
@create_attrs %{is_public: true, name: "some name"}
@update_attrs %{is_public: false, name: "some updated name"}
@invalid_attrs %{is_public: nil, name: nil}
defp fixture(:list) do
{:ok, list} = Lists.create_list(@create_attrs)
list
end
defp create_list(_) do
list = fixture(:list)
%{list: list}
end
describe "Index" do
setup [:create_list]
test "lists all lists", %{conn: conn, list: list} do
{:ok, _index_live, html} = live(conn, Routes.list_index_path(conn, :index))
assert html =~ "Listing Lists"
assert html =~ list.name
end
test "saves new list", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.list_index_path(conn, :index))
assert index_live |> element("a", "New List") |> render_click() =~
"New List"
assert_patch(index_live, Routes.list_index_path(conn, :new))
assert index_live
|> form("#list-form", list: @invalid_attrs)
|> render_change() =~ "can&apos;t be blank"
{:ok, _, html} =
index_live
|> form("#list-form", list: @create_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.list_index_path(conn, :index))
assert html =~ "List created successfully"
assert html =~ "some name"
end
test "updates list in listing", %{conn: conn, list: list} do
{:ok, index_live, _html} = live(conn, Routes.list_index_path(conn, :index))
assert index_live |> element("#list-#{list.id} a", "Edit") |> render_click() =~
"Edit List"
assert_patch(index_live, Routes.list_index_path(conn, :edit, list))
assert index_live
|> form("#list-form", list: @invalid_attrs)
|> render_change() =~ "can&apos;t be blank"
{:ok, _, html} =
index_live
|> form("#list-form", list: @update_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.list_index_path(conn, :index))
assert html =~ "List updated successfully"
assert html =~ "some updated name"
end
test "deletes list in listing", %{conn: conn, list: list} do
{:ok, index_live, _html} = live(conn, Routes.list_index_path(conn, :index))
assert index_live |> element("#list-#{list.id} a", "Delete") |> render_click()
refute has_element?(index_live, "#list-#{list.id}")
end
end
describe "Show" do
setup [:create_list]
test "displays list", %{conn: conn, list: list} do
{:ok, _show_live, html} = live(conn, Routes.list_show_path(conn, :show, list))
assert html =~ "Show List"
assert html =~ list.name
end
test "updates list within modal", %{conn: conn, list: list} do
{:ok, show_live, _html} = live(conn, Routes.list_show_path(conn, :show, list))
assert show_live |> element("a", "Edit") |> render_click() =~
"Edit List"
assert_patch(show_live, Routes.list_show_path(conn, :edit, list))
assert show_live
|> form("#list-form", list: @invalid_attrs)
|> render_change() =~ "can&apos;t be blank"
{:ok, _, html} =
show_live
|> form("#list-form", list: @update_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.list_show_path(conn, :show, list))
assert html =~ "List updated successfully"
assert html =~ "some updated name"
end
end
end
Loading…
Cancel
Save