From a151bfcee74c94fd88d20f09bcbad606222ce5f0 Mon Sep 17 00:00:00 2001
From: Adam Piontek <adam@73k.us>
Date: Sat, 6 Mar 2021 13:48:13 -0500
Subject: [PATCH] initial shift template migration & schema working with user
 field/assoc for default shift template

---
 .iex.exs                                      |   2 +
 lib/shift73k/accounts/user.ex                 |   7 ++
 lib/shift73k/shift_templates.ex               | 104 ++++++++++++++++
 .../shift_templates/shift_template.ex         |  46 +++++++
 .../shift_template_live/form_component.ex     |  55 +++++++++
 .../form_component.html.leex                  |  42 +++++++
 .../live/shift_template_live/index.ex         |  46 +++++++
 .../live/shift_template_live/index.html.leex  |  49 ++++++++
 .../live/shift_template_live/show.ex          |  21 ++++
 .../live/shift_template_live/show.html.leex   |  57 +++++++++
 lib/shift73k_web/router.ex                    |  13 +-
 .../20210306171754_create_shift_templates.exs |  22 ++++
 ...06173113_add_user_default_shift_column.exs |   9 ++
 priv/repo/seeds.exs                           |   2 +-
 test/shift73k/shift_templates_test.exs        |  78 ++++++++++++
 .../live/shift_template_live_test.exs         | 116 ++++++++++++++++++
 16 files changed, 665 insertions(+), 4 deletions(-)
 create mode 100644 lib/shift73k/shift_templates.ex
 create mode 100644 lib/shift73k/shift_templates/shift_template.ex
 create mode 100644 lib/shift73k_web/live/shift_template_live/form_component.ex
 create mode 100644 lib/shift73k_web/live/shift_template_live/form_component.html.leex
 create mode 100644 lib/shift73k_web/live/shift_template_live/index.ex
 create mode 100644 lib/shift73k_web/live/shift_template_live/index.html.leex
 create mode 100644 lib/shift73k_web/live/shift_template_live/show.ex
 create mode 100644 lib/shift73k_web/live/shift_template_live/show.html.leex
 create mode 100644 priv/repo/migrations/20210306171754_create_shift_templates.exs
 create mode 100644 priv/repo/migrations/20210306173113_add_user_default_shift_column.exs
 create mode 100644 test/shift73k/shift_templates_test.exs
 create mode 100644 test/shift73k_web/live/shift_template_live_test.exs

diff --git a/.iex.exs b/.iex.exs
index 02446b6d..052498c3 100644
--- a/.iex.exs
+++ b/.iex.exs
@@ -3,3 +3,5 @@ import Ecto.Query
 alias Shift73k.Repo
 alias Shift73k.Accounts
 alias Shift73k.Accounts.User
+alias Shift73k.ShiftTemplates, as: STemplates
+alias Shift73k.ShiftTemplates.ShiftTemplate, as: STemplate
diff --git a/lib/shift73k/accounts/user.ex b/lib/shift73k/accounts/user.ex
index 57e0df45..b63fe6ce 100644
--- a/lib/shift73k/accounts/user.ex
+++ b/lib/shift73k/accounts/user.ex
@@ -3,6 +3,8 @@ defmodule Shift73k.Accounts.User do
   import Ecto.Changeset
   import EctoEnum
 
+  alias Shift73k.ShiftTemplates.ShiftTemplate
+
   @roles [
     user: "Basic user level",
     manager: "Can create users, update user emails & passwords",
@@ -25,6 +27,11 @@ defmodule Shift73k.Accounts.User do
     field(:confirmed_at, :naive_datetime)
 
     field(:role, RolesEnum, default: :user)
+
+    has_many(:shift_templates, ShiftTemplate)
+    # has_one(:default_shift_template, ShiftTemplate, references: :default_shift_template_id)
+    belongs_to(:default_shift_template, ShiftTemplate)
+
     timestamps()
   end
 
diff --git a/lib/shift73k/shift_templates.ex b/lib/shift73k/shift_templates.ex
new file mode 100644
index 00000000..cf53408f
--- /dev/null
+++ b/lib/shift73k/shift_templates.ex
@@ -0,0 +1,104 @@
+defmodule Shift73k.ShiftTemplates do
+  @moduledoc """
+  The ShiftTemplates context.
+  """
+
+  import Ecto.Query, warn: false
+  alias Shift73k.Repo
+
+  alias Shift73k.ShiftTemplates.ShiftTemplate
+
+  @doc """
+  Returns the list of shift_templates.
+
+  ## Examples
+
+      iex> list_shift_templates()
+      [%ShiftTemplate{}, ...]
+
+  """
+  def list_shift_templates do
+    Repo.all(ShiftTemplate)
+  end
+
+  @doc """
+  Gets a single shift_template.
+
+  Raises `Ecto.NoResultsError` if the Shift template does not exist.
+
+  ## Examples
+
+      iex> get_shift_template!(123)
+      %ShiftTemplate{}
+
+      iex> get_shift_template!(456)
+      ** (Ecto.NoResultsError)
+
+  """
+  def get_shift_template!(id), do: Repo.get!(ShiftTemplate, id)
+
+  @doc """
+  Creates a shift_template.
+
+  ## Examples
+
+      iex> create_shift_template(%{field: value})
+      {:ok, %ShiftTemplate{}}
+
+      iex> create_shift_template(%{field: bad_value})
+      {:error, %Ecto.Changeset{}}
+
+  """
+  def create_shift_template(attrs \\ %{}) do
+    %ShiftTemplate{}
+    |> ShiftTemplate.changeset(attrs)
+    |> Repo.insert()
+  end
+
+  @doc """
+  Updates a shift_template.
+
+  ## Examples
+
+      iex> update_shift_template(shift_template, %{field: new_value})
+      {:ok, %ShiftTemplate{}}
+
+      iex> update_shift_template(shift_template, %{field: bad_value})
+      {:error, %Ecto.Changeset{}}
+
+  """
+  def update_shift_template(%ShiftTemplate{} = shift_template, attrs) do
+    shift_template
+    |> ShiftTemplate.changeset(attrs)
+    |> Repo.update()
+  end
+
+  @doc """
+  Deletes a shift_template.
+
+  ## Examples
+
+      iex> delete_shift_template(shift_template)
+      {:ok, %ShiftTemplate{}}
+
+      iex> delete_shift_template(shift_template)
+      {:error, %Ecto.Changeset{}}
+
+  """
+  def delete_shift_template(%ShiftTemplate{} = shift_template) do
+    Repo.delete(shift_template)
+  end
+
+  @doc """
+  Returns an `%Ecto.Changeset{}` for tracking shift_template changes.
+
+  ## Examples
+
+      iex> change_shift_template(shift_template)
+      %Ecto.Changeset{data: %ShiftTemplate{}}
+
+  """
+  def change_shift_template(%ShiftTemplate{} = shift_template, attrs \\ %{}) do
+    ShiftTemplate.changeset(shift_template, attrs)
+  end
+end
diff --git a/lib/shift73k/shift_templates/shift_template.ex b/lib/shift73k/shift_templates/shift_template.ex
new file mode 100644
index 00000000..48254c9c
--- /dev/null
+++ b/lib/shift73k/shift_templates/shift_template.ex
@@ -0,0 +1,46 @@
+defmodule Shift73k.ShiftTemplates.ShiftTemplate do
+  use Ecto.Schema
+  import Ecto.Changeset
+
+  @primary_key {:id, :binary_id, autogenerate: true}
+  @foreign_key_type :binary_id
+  schema "shift_templates" do
+    field :label, :string
+    field :subject, :string
+    field :description, :string
+    field :location, :string
+    field :timezone, :string
+    field :start_time, :time
+    field :length_hours, :integer
+    field :length_minutes, :integer
+
+    belongs_to(:user, Shift73k.Accounts.User)
+
+    timestamps()
+  end
+
+  @doc false
+  def changeset(shift_template, attrs) do
+    shift_template
+    |> cast(attrs, [
+      :label,
+      :subject,
+      :description,
+      :location,
+      :timezone,
+      :start_time,
+      :length_hours,
+      :length_minutes,
+      :user_id
+    ])
+    |> validate_required([
+      :subject,
+      :timezone,
+      :start_time,
+      :length_hours
+    ])
+    |> validate_number(:length_hours, greater_than_or_equal_to: 0, less_than_or_equal_to: 24)
+    |> validate_number(:length_minutes, greater_than_or_equal_to: 0, less_than: 60)
+    |> validate_inclusion(:timezone, Tzdata.zone_list())
+  end
+end
diff --git a/lib/shift73k_web/live/shift_template_live/form_component.ex b/lib/shift73k_web/live/shift_template_live/form_component.ex
new file mode 100644
index 00000000..b108ea75
--- /dev/null
+++ b/lib/shift73k_web/live/shift_template_live/form_component.ex
@@ -0,0 +1,55 @@
+defmodule Shift73kWeb.ShiftTemplateLive.FormComponent do
+  use Shift73kWeb, :live_component
+
+  alias Shift73k.ShiftTemplates
+
+  @impl true
+  def update(%{shift_template: shift_template} = assigns, socket) do
+    changeset = ShiftTemplates.change_shift_template(shift_template)
+
+    {:ok,
+     socket
+     |> assign(assigns)
+     |> assign(:changeset, changeset)}
+  end
+
+  @impl true
+  def handle_event("validate", %{"shift_template" => shift_template_params}, socket) do
+    changeset =
+      socket.assigns.shift_template
+      |> ShiftTemplates.change_shift_template(shift_template_params)
+      |> Map.put(:action, :validate)
+
+    {:noreply, assign(socket, :changeset, changeset)}
+  end
+
+  def handle_event("save", %{"shift_template" => shift_template_params}, socket) do
+    save_shift_template(socket, socket.assigns.action, shift_template_params)
+  end
+
+  defp save_shift_template(socket, :edit, shift_template_params) do
+    case ShiftTemplates.update_shift_template(socket.assigns.shift_template, shift_template_params) do
+      {:ok, _shift_template} ->
+        {:noreply,
+         socket
+         |> put_flash(:info, "Shift template updated successfully")
+         |> push_redirect(to: socket.assigns.return_to)}
+
+      {:error, %Ecto.Changeset{} = changeset} ->
+        {:noreply, assign(socket, :changeset, changeset)}
+    end
+  end
+
+  defp save_shift_template(socket, :new, shift_template_params) do
+    case ShiftTemplates.create_shift_template(shift_template_params) do
+      {:ok, _shift_template} ->
+        {:noreply,
+         socket
+         |> put_flash(:info, "Shift template 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/shift73k_web/live/shift_template_live/form_component.html.leex b/lib/shift73k_web/live/shift_template_live/form_component.html.leex
new file mode 100644
index 00000000..014d6a61
--- /dev/null
+++ b/lib/shift73k_web/live/shift_template_live/form_component.html.leex
@@ -0,0 +1,42 @@
+<h2><%= @title %></h2>
+
+<%= f = form_for @changeset, "#",
+  id: "shift_template-form",
+  phx_target: @myself,
+  phx_change: "validate",
+  phx_submit: "save" %>
+
+  <%= label f, :label %>
+  <%= text_input f, :label %>
+  <%= error_tag f, :label %>
+
+  <%= label f, :subject %>
+  <%= text_input f, :subject %>
+  <%= error_tag f, :subject %>
+
+  <%= label f, :description %>
+  <%= text_input f, :description %>
+  <%= error_tag f, :description %>
+
+  <%= label f, :location %>
+  <%= text_input f, :location %>
+  <%= error_tag f, :location %>
+
+  <%= label f, :timezone %>
+  <%= text_input f, :timezone %>
+  <%= error_tag f, :timezone %>
+
+  <%= label f, :start_time %>
+  <%= time_select f, :start_time %>
+  <%= error_tag f, :start_time %>
+
+  <%= label f, :length_hours %>
+  <%= number_input f, :length_hours %>
+  <%= error_tag f, :length_hours %>
+
+  <%= label f, :length_minutes %>
+  <%= number_input f, :length_minutes %>
+  <%= error_tag f, :length_minutes %>
+
+  <%= submit "Save", phx_disable_with: "Saving..." %>
+</form>
diff --git a/lib/shift73k_web/live/shift_template_live/index.ex b/lib/shift73k_web/live/shift_template_live/index.ex
new file mode 100644
index 00000000..98a311ab
--- /dev/null
+++ b/lib/shift73k_web/live/shift_template_live/index.ex
@@ -0,0 +1,46 @@
+defmodule Shift73kWeb.ShiftTemplateLive.Index do
+  use Shift73kWeb, :live_view
+
+  alias Shift73k.ShiftTemplates
+  alias Shift73k.ShiftTemplates.ShiftTemplate
+
+  @impl true
+  def mount(_params, _session, socket) do
+    {:ok, assign(socket, :shift_templates, list_shift_templates())}
+  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 Shift template")
+    |> assign(:shift_template, ShiftTemplates.get_shift_template!(id))
+  end
+
+  defp apply_action(socket, :new, _params) do
+    socket
+    |> assign(:page_title, "New Shift template")
+    |> assign(:shift_template, %ShiftTemplate{})
+  end
+
+  defp apply_action(socket, :index, _params) do
+    socket
+    |> assign(:page_title, "Listing Shift templates")
+    |> assign(:shift_template, nil)
+  end
+
+  @impl true
+  def handle_event("delete", %{"id" => id}, socket) do
+    shift_template = ShiftTemplates.get_shift_template!(id)
+    {:ok, _} = ShiftTemplates.delete_shift_template(shift_template)
+
+    {:noreply, assign(socket, :shift_templates, list_shift_templates())}
+  end
+
+  defp list_shift_templates do
+    ShiftTemplates.list_shift_templates()
+  end
+end
diff --git a/lib/shift73k_web/live/shift_template_live/index.html.leex b/lib/shift73k_web/live/shift_template_live/index.html.leex
new file mode 100644
index 00000000..6f92d575
--- /dev/null
+++ b/lib/shift73k_web/live/shift_template_live/index.html.leex
@@ -0,0 +1,49 @@
+<h1>Listing Shift templates</h1>
+
+<%= if @live_action in [:new, :edit] do %>
+  <%= live_modal @socket, Shift73kWeb.ShiftTemplateLive.FormComponent,
+    id: @shift_template.id || :new,
+    title: @page_title,
+    action: @live_action,
+    shift_template: @shift_template,
+    return_to: Routes.shift_template_index_path(@socket, :index) %>
+<% end %>
+
+<table>
+  <thead>
+    <tr>
+      <th>Label</th>
+      <th>Subject</th>
+      <th>Description</th>
+      <th>Location</th>
+      <th>Timezone</th>
+      <th>Start time</th>
+      <th>Length hours</th>
+      <th>Length minutes</th>
+
+      <th></th>
+    </tr>
+  </thead>
+  <tbody id="shift_templates">
+    <%= for shift_template <- @shift_templates do %>
+      <tr id="shift_template-<%= shift_template.id %>">
+        <td><%= shift_template.label %></td>
+        <td><%= shift_template.subject %></td>
+        <td><%= shift_template.description %></td>
+        <td><%= shift_template.location %></td>
+        <td><%= shift_template.timezone %></td>
+        <td><%= shift_template.start_time %></td>
+        <td><%= shift_template.length_hours %></td>
+        <td><%= shift_template.length_minutes %></td>
+
+        <td>
+          <span><%= live_redirect "Show", to: Routes.shift_template_show_path(@socket, :show, shift_template) %></span>
+          <span><%= live_patch "Edit", to: Routes.shift_template_index_path(@socket, :edit, shift_template) %></span>
+          <span><%= link "Delete", to: "#", phx_click: "delete", phx_value_id: shift_template.id, data: [confirm: "Are you sure?"] %></span>
+        </td>
+      </tr>
+    <% end %>
+  </tbody>
+</table>
+
+<span><%= live_patch "New Shift template", to: Routes.shift_template_index_path(@socket, :new) %></span>
diff --git a/lib/shift73k_web/live/shift_template_live/show.ex b/lib/shift73k_web/live/shift_template_live/show.ex
new file mode 100644
index 00000000..084a69e9
--- /dev/null
+++ b/lib/shift73k_web/live/shift_template_live/show.ex
@@ -0,0 +1,21 @@
+defmodule Shift73kWeb.ShiftTemplateLive.Show do
+  use Shift73kWeb, :live_view
+
+  alias Shift73k.ShiftTemplates
+
+  @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(:shift_template, ShiftTemplates.get_shift_template!(id))}
+  end
+
+  defp page_title(:show), do: "Show Shift template"
+  defp page_title(:edit), do: "Edit Shift template"
+end
diff --git a/lib/shift73k_web/live/shift_template_live/show.html.leex b/lib/shift73k_web/live/shift_template_live/show.html.leex
new file mode 100644
index 00000000..f24da22a
--- /dev/null
+++ b/lib/shift73k_web/live/shift_template_live/show.html.leex
@@ -0,0 +1,57 @@
+<h1>Show Shift template</h1>
+
+<%= if @live_action in [:edit] do %>
+  <%= live_modal @socket, Shift73kWeb.ShiftTemplateLive.FormComponent,
+    id: @shift_template.id,
+    title: @page_title,
+    action: @live_action,
+    shift_template: @shift_template,
+    return_to: Routes.shift_template_show_path(@socket, :show, @shift_template) %>
+<% end %>
+
+<ul>
+
+  <li>
+    <strong>Label:</strong>
+    <%= @shift_template.label %>
+  </li>
+
+  <li>
+    <strong>Subject:</strong>
+    <%= @shift_template.subject %>
+  </li>
+
+  <li>
+    <strong>Description:</strong>
+    <%= @shift_template.description %>
+  </li>
+
+  <li>
+    <strong>Location:</strong>
+    <%= @shift_template.location %>
+  </li>
+
+  <li>
+    <strong>Timezone:</strong>
+    <%= @shift_template.timezone %>
+  </li>
+
+  <li>
+    <strong>Start time:</strong>
+    <%= @shift_template.start_time %>
+  </li>
+
+  <li>
+    <strong>Length hours:</strong>
+    <%= @shift_template.length_hours %>
+  </li>
+
+  <li>
+    <strong>Length minutes:</strong>
+    <%= @shift_template.length_minutes %>
+  </li>
+
+</ul>
+
+<span><%= live_patch "Edit", to: Routes.shift_template_show_path(@socket, :edit, @shift_template), class: "button" %></span>
+<span><%= live_redirect "Back", to: Routes.shift_template_index_path(@socket, :index) %></span>
diff --git a/lib/shift73k_web/router.ex b/lib/shift73k_web/router.ex
index 2545ec96..fb7798db 100644
--- a/lib/shift73k_web/router.ex
+++ b/lib/shift73k_web/router.ex
@@ -88,9 +88,16 @@ defmodule Shift73kWeb.Router do
     get("/users/confirm/:token", UserConfirmationController, :confirm)
   end
 
-  # scope "/", Shift73kWeb do
-  #   pipe_through([:browser, :require_authenticated_user, :user])
-  # end
+  scope "/", Shift73kWeb do
+    pipe_through([:browser, :require_authenticated_user, :user])
+
+    live "/shift_templates", ShiftTemplateLive.Index, :index
+    live "/shift_templates/new", ShiftTemplateLive.Index, :new
+    live "/shift_templates/:id/edit", ShiftTemplateLive.Index, :edit
+
+    live "/shift_templates/:id", ShiftTemplateLive.Show, :show
+    live "/shift_templates/:id/show/edit", ShiftTemplateLive.Show, :edit
+  end
 
   # scope "/", Shift73kWeb do
   #   pipe_through([:browser, :require_authenticated_user, :admin])
diff --git a/priv/repo/migrations/20210306171754_create_shift_templates.exs b/priv/repo/migrations/20210306171754_create_shift_templates.exs
new file mode 100644
index 00000000..934eecae
--- /dev/null
+++ b/priv/repo/migrations/20210306171754_create_shift_templates.exs
@@ -0,0 +1,22 @@
+defmodule Shift73k.Repo.Migrations.CreateShiftTemplates do
+  use Ecto.Migration
+
+  def change do
+    create table(:shift_templates, primary_key: false) do
+      add :id, :binary_id, primary_key: true
+      add :label, :string
+      add :subject, :string, null: false
+      add :description, :string
+      add :location, :string
+      add :timezone, :string, null: false
+      add :start_time, :time, null: false
+      add :length_hours, :integer, null: false
+      add :length_minutes, :integer
+      add :user_id, references(:users, on_delete: :nothing, type: :binary_id)
+
+      timestamps()
+    end
+
+    create index(:shift_templates, [:user_id])
+  end
+end
diff --git a/priv/repo/migrations/20210306173113_add_user_default_shift_column.exs b/priv/repo/migrations/20210306173113_add_user_default_shift_column.exs
new file mode 100644
index 00000000..751b52e5
--- /dev/null
+++ b/priv/repo/migrations/20210306173113_add_user_default_shift_column.exs
@@ -0,0 +1,9 @@
+defmodule Shift73k.Repo.Migrations.AddUserDefaultShiftColumn do
+  use Ecto.Migration
+
+  def change do
+    alter table(:users) do
+      add(:default_shift_template_id, references(:shift_templates, type: :binary_id, on_delete: :delete_all))
+    end
+  end
+end
diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs
index ebadb34b..29628716 100644
--- a/priv/repo/seeds.exs
+++ b/priv/repo/seeds.exs
@@ -46,7 +46,7 @@ this_path = Path.dirname(__ENV__.file)
 
 users_json = Path.join(this_path, "MOCK_DATA_users.json")
 
-count_to_take = 65
+count_to_take = 15
 
 mock_users = users_json |> File.read!() |> Jason.decode!() |> Enum.take_random(count_to_take)
 
diff --git a/test/shift73k/shift_templates_test.exs b/test/shift73k/shift_templates_test.exs
new file mode 100644
index 00000000..cd02f774
--- /dev/null
+++ b/test/shift73k/shift_templates_test.exs
@@ -0,0 +1,78 @@
+defmodule Shift73k.ShiftTemplatesTest do
+  use Shift73k.DataCase
+
+  alias Shift73k.ShiftTemplates
+
+  describe "shift_templates" do
+    alias Shift73k.ShiftTemplates.ShiftTemplate
+
+    @valid_attrs %{description: "some description", label: "some label", length_hours: 42, length_minutes: 42, location: "some location", start_time: ~T[14:00:00], subject: "some subject", timezone: "some timezone"}
+    @update_attrs %{description: "some updated description", label: "some updated label", length_hours: 43, length_minutes: 43, location: "some updated location", start_time: ~T[15:01:01], subject: "some updated subject", timezone: "some updated timezone"}
+    @invalid_attrs %{description: nil, label: nil, length_hours: nil, length_minutes: nil, location: nil, start_time: nil, subject: nil, timezone: nil}
+
+    def shift_template_fixture(attrs \\ %{}) do
+      {:ok, shift_template} =
+        attrs
+        |> Enum.into(@valid_attrs)
+        |> ShiftTemplates.create_shift_template()
+
+      shift_template
+    end
+
+    test "list_shift_templates/0 returns all shift_templates" do
+      shift_template = shift_template_fixture()
+      assert ShiftTemplates.list_shift_templates() == [shift_template]
+    end
+
+    test "get_shift_template!/1 returns the shift_template with given id" do
+      shift_template = shift_template_fixture()
+      assert ShiftTemplates.get_shift_template!(shift_template.id) == shift_template
+    end
+
+    test "create_shift_template/1 with valid data creates a shift_template" do
+      assert {:ok, %ShiftTemplate{} = shift_template} = ShiftTemplates.create_shift_template(@valid_attrs)
+      assert shift_template.description == "some description"
+      assert shift_template.label == "some label"
+      assert shift_template.length_hours == 42
+      assert shift_template.length_minutes == 42
+      assert shift_template.location == "some location"
+      assert shift_template.start_time == ~T[14:00:00]
+      assert shift_template.subject == "some subject"
+      assert shift_template.timezone == "some timezone"
+    end
+
+    test "create_shift_template/1 with invalid data returns error changeset" do
+      assert {:error, %Ecto.Changeset{}} = ShiftTemplates.create_shift_template(@invalid_attrs)
+    end
+
+    test "update_shift_template/2 with valid data updates the shift_template" do
+      shift_template = shift_template_fixture()
+      assert {:ok, %ShiftTemplate{} = shift_template} = ShiftTemplates.update_shift_template(shift_template, @update_attrs)
+      assert shift_template.description == "some updated description"
+      assert shift_template.label == "some updated label"
+      assert shift_template.length_hours == 43
+      assert shift_template.length_minutes == 43
+      assert shift_template.location == "some updated location"
+      assert shift_template.start_time == ~T[15:01:01]
+      assert shift_template.subject == "some updated subject"
+      assert shift_template.timezone == "some updated timezone"
+    end
+
+    test "update_shift_template/2 with invalid data returns error changeset" do
+      shift_template = shift_template_fixture()
+      assert {:error, %Ecto.Changeset{}} = ShiftTemplates.update_shift_template(shift_template, @invalid_attrs)
+      assert shift_template == ShiftTemplates.get_shift_template!(shift_template.id)
+    end
+
+    test "delete_shift_template/1 deletes the shift_template" do
+      shift_template = shift_template_fixture()
+      assert {:ok, %ShiftTemplate{}} = ShiftTemplates.delete_shift_template(shift_template)
+      assert_raise Ecto.NoResultsError, fn -> ShiftTemplates.get_shift_template!(shift_template.id) end
+    end
+
+    test "change_shift_template/1 returns a shift_template changeset" do
+      shift_template = shift_template_fixture()
+      assert %Ecto.Changeset{} = ShiftTemplates.change_shift_template(shift_template)
+    end
+  end
+end
diff --git a/test/shift73k_web/live/shift_template_live_test.exs b/test/shift73k_web/live/shift_template_live_test.exs
new file mode 100644
index 00000000..6003463f
--- /dev/null
+++ b/test/shift73k_web/live/shift_template_live_test.exs
@@ -0,0 +1,116 @@
+defmodule Shift73kWeb.ShiftTemplateLiveTest do
+  use Shift73kWeb.ConnCase
+
+  import Phoenix.LiveViewTest
+
+  alias Shift73k.ShiftTemplates
+
+  @create_attrs %{description: "some description", label: "some label", length_hours: 42, length_minutes: 42, location: "some location", start_time: ~T[14:00:00], subject: "some subject", timezone: "some timezone"}
+  @update_attrs %{description: "some updated description", label: "some updated label", length_hours: 43, length_minutes: 43, location: "some updated location", start_time: ~T[15:01:01], subject: "some updated subject", timezone: "some updated timezone"}
+  @invalid_attrs %{description: nil, label: nil, length_hours: nil, length_minutes: nil, location: nil, start_time: nil, subject: nil, timezone: nil}
+
+  defp fixture(:shift_template) do
+    {:ok, shift_template} = ShiftTemplates.create_shift_template(@create_attrs)
+    shift_template
+  end
+
+  defp create_shift_template(_) do
+    shift_template = fixture(:shift_template)
+    %{shift_template: shift_template}
+  end
+
+  describe "Index" do
+    setup [:create_shift_template]
+
+    test "lists all shift_templates", %{conn: conn, shift_template: shift_template} do
+      {:ok, _index_live, html} = live(conn, Routes.shift_template_index_path(conn, :index))
+
+      assert html =~ "Listing Shift templates"
+      assert html =~ shift_template.description
+    end
+
+    test "saves new shift_template", %{conn: conn} do
+      {:ok, index_live, _html} = live(conn, Routes.shift_template_index_path(conn, :index))
+
+      assert index_live |> element("a", "New Shift template") |> render_click() =~
+               "New Shift template"
+
+      assert_patch(index_live, Routes.shift_template_index_path(conn, :new))
+
+      assert index_live
+             |> form("#shift_template-form", shift_template: @invalid_attrs)
+             |> render_change() =~ "can&apos;t be blank"
+
+      {:ok, _, html} =
+        index_live
+        |> form("#shift_template-form", shift_template: @create_attrs)
+        |> render_submit()
+        |> follow_redirect(conn, Routes.shift_template_index_path(conn, :index))
+
+      assert html =~ "Shift template created successfully"
+      assert html =~ "some description"
+    end
+
+    test "updates shift_template in listing", %{conn: conn, shift_template: shift_template} do
+      {:ok, index_live, _html} = live(conn, Routes.shift_template_index_path(conn, :index))
+
+      assert index_live |> element("#shift_template-#{shift_template.id} a", "Edit") |> render_click() =~
+               "Edit Shift template"
+
+      assert_patch(index_live, Routes.shift_template_index_path(conn, :edit, shift_template))
+
+      assert index_live
+             |> form("#shift_template-form", shift_template: @invalid_attrs)
+             |> render_change() =~ "can&apos;t be blank"
+
+      {:ok, _, html} =
+        index_live
+        |> form("#shift_template-form", shift_template: @update_attrs)
+        |> render_submit()
+        |> follow_redirect(conn, Routes.shift_template_index_path(conn, :index))
+
+      assert html =~ "Shift template updated successfully"
+      assert html =~ "some updated description"
+    end
+
+    test "deletes shift_template in listing", %{conn: conn, shift_template: shift_template} do
+      {:ok, index_live, _html} = live(conn, Routes.shift_template_index_path(conn, :index))
+
+      assert index_live |> element("#shift_template-#{shift_template.id} a", "Delete") |> render_click()
+      refute has_element?(index_live, "#shift_template-#{shift_template.id}")
+    end
+  end
+
+  describe "Show" do
+    setup [:create_shift_template]
+
+    test "displays shift_template", %{conn: conn, shift_template: shift_template} do
+      {:ok, _show_live, html} = live(conn, Routes.shift_template_show_path(conn, :show, shift_template))
+
+      assert html =~ "Show Shift template"
+      assert html =~ shift_template.description
+    end
+
+    test "updates shift_template within modal", %{conn: conn, shift_template: shift_template} do
+      {:ok, show_live, _html} = live(conn, Routes.shift_template_show_path(conn, :show, shift_template))
+
+      assert show_live |> element("a", "Edit") |> render_click() =~
+               "Edit Shift template"
+
+      assert_patch(show_live, Routes.shift_template_show_path(conn, :edit, shift_template))
+
+      assert show_live
+             |> form("#shift_template-form", shift_template: @invalid_attrs)
+             |> render_change() =~ "can&apos;t be blank"
+
+      {:ok, _, html} =
+        show_live
+        |> form("#shift_template-form", shift_template: @update_attrs)
+        |> render_submit()
+        |> follow_redirect(conn, Routes.shift_template_show_path(conn, :show, shift_template))
+
+      assert html =~ "Shift template updated successfully"
+      assert html =~ "some updated description"
+    end
+  end
+end