From 57c8b5b322b9d34ef2a3a987f5d269082ff1014a Mon Sep 17 00:00:00 2001
From: Adam Piontek <adam@73k.us>
Date: Sat, 6 Mar 2021 20:16:56 -0500
Subject: [PATCH] initial shift template live view progress

---
 .iex.exs                                      |  4 +-
 assets/js/app.js                              |  5 +-
 lib/shift73k/shift_templates.ex               |  5 ++
 .../shift_templates/shift_template.ex         | 13 +++--
 .../live/shift_template_live/index.ex         | 54 ++++++++++++++++---
 .../live/shift_template_live/index.html.leex  | 28 ++++++----
 lib/shift73k_web/roles.ex                     | 16 +++---
 lib/shift73k_web/router.ex                    | 10 ++--
 .../templates/layout/_navbar.html.eex         |  2 +-
 9 files changed, 98 insertions(+), 39 deletions(-)

diff --git a/.iex.exs b/.iex.exs
index 052498c3..99529970 100644
--- a/.iex.exs
+++ b/.iex.exs
@@ -3,5 +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
+alias Shift73k.ShiftTemplates
+alias Shift73k.ShiftTemplates.ShiftTemplate
diff --git a/assets/js/app.js b/assets/js/app.js
index 63a63a96..66c975dd 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -5,7 +5,7 @@ import "../css/app.scss";
 
 // Import icons for sprite-loader
 // navbar brand icon
-import "../node_modules/@mdi/svg/svg/skull-crossbones.svg"; // brand
+import "../node_modules/bootstrap-icons/icons/calendar3-week.svg"; // brand
 // menus etc
 import "../node_modules/bootstrap-icons/icons/person-circle.svg"; // accounts menu
 import "../node_modules/bootstrap-icons/icons/person-plus.svg"; // new user / register
@@ -35,6 +35,9 @@ import "../node_modules/bootstrap-icons/icons/arrow-repeat.svg"; // resend confi
 import "../node_modules/bootstrap-icons/icons/door-open.svg"; // log in header
 import "../node_modules/@mdi/svg/svg/head-question-outline.svg"; // forgot password
 import "../node_modules/bootstrap-icons/icons/people.svg"; // users management
+// calendar/event icons
+import "../node_modules/bootstrap-icons/icons/calendar3-event.svg"; // brand
+import "../node_modules/bootstrap-icons/icons/clock-history.svg"; // brand
 
 // webpack automatically bundles all modules in your
 // entry points. Those entry points can be configured
diff --git a/lib/shift73k/shift_templates.ex b/lib/shift73k/shift_templates.ex
index cf53408f..c3079102 100644
--- a/lib/shift73k/shift_templates.ex
+++ b/lib/shift73k/shift_templates.ex
@@ -21,6 +21,11 @@ defmodule Shift73k.ShiftTemplates do
     Repo.all(ShiftTemplate)
   end
 
+  def list_shift_templates_by_user_id(user_id) do
+    (from s in ShiftTemplate, where: s.user_id == ^user_id)
+    |> Repo.all()
+  end
+
   @doc """
   Gets a single shift_template.
 
diff --git a/lib/shift73k/shift_templates/shift_template.ex b/lib/shift73k/shift_templates/shift_template.ex
index 48254c9c..a81f5eef 100644
--- a/lib/shift73k/shift_templates/shift_template.ex
+++ b/lib/shift73k/shift_templates/shift_template.ex
@@ -2,17 +2,20 @@ defmodule Shift73k.ShiftTemplates.ShiftTemplate do
   use Ecto.Schema
   import Ecto.Changeset
 
+  @app_vars Application.get_env(:shift73k, :app_global_vars, time_zone: "America/New_York")
+  @time_zone @app_vars[:time_zone]
+
   @primary_key {:id, :binary_id, autogenerate: true}
   @foreign_key_type :binary_id
   schema "shift_templates" do
     field :label, :string
-    field :subject, :string
+    field :subject, :string, default: "My Work Shift"
     field :description, :string
     field :location, :string
-    field :timezone, :string
-    field :start_time, :time
-    field :length_hours, :integer
-    field :length_minutes, :integer
+    field :timezone, :string, default: @time_zone
+    field :start_time, :time, default: ~T[09:00:00]
+    field :length_hours, :integer, default: 8
+    field :length_minutes, :integer, default: 0
 
     belongs_to(:user, Shift73k.Accounts.User)
 
diff --git a/lib/shift73k_web/live/shift_template_live/index.ex b/lib/shift73k_web/live/shift_template_live/index.ex
index 98a311ab..65efc1cc 100644
--- a/lib/shift73k_web/live/shift_template_live/index.ex
+++ b/lib/shift73k_web/live/shift_template_live/index.ex
@@ -3,15 +3,36 @@ defmodule Shift73kWeb.ShiftTemplateLive.Index do
 
   alias Shift73k.ShiftTemplates
   alias Shift73k.ShiftTemplates.ShiftTemplate
+  alias Shift73kWeb.Roles
 
   @impl true
-  def mount(_params, _session, socket) do
-    {:ok, assign(socket, :shift_templates, list_shift_templates())}
+  def mount(_params, session, socket) do
+    # {:ok, assign(socket, :shift_templates, list_shift_templates())}
+    socket
+    |> assign_defaults(session)
+    |> live_okreply()
   end
 
   @impl true
   def handle_params(params, _url, socket) do
-    {:noreply, apply_action(socket, socket.assigns.live_action, params)}
+    current_user = socket.assigns.current_user
+    live_action = socket.assigns.live_action
+    shift_template = shift_template_from_params(params)
+
+
+    if Roles.can?(current_user, shift_template, live_action) do
+      socket
+      |> assign_shift_templates()
+      |> assign(:modal_return_to, Routes.shift_template_index_path(socket, :index))
+      |> assign(:delete_shift_template, nil)
+      |> apply_action(socket.assigns.live_action, params)
+      |> live_noreply()
+    else
+      socket
+      |> put_flash(:error, "Unauthorised")
+      |> redirect(to: "/")
+      |> live_noreply()
+    end
   end
 
   defp apply_action(socket, :edit, %{"id" => id}) do
@@ -32,15 +53,36 @@ defmodule Shift73kWeb.ShiftTemplateLive.Index do
     |> assign(:shift_template, nil)
   end
 
+  defp assign_shift_templates(socket) do
+    %User{id: uid} = socket.assigns.current_user
+    user_shifts = ShiftTemplates.list_shift_templates_by_user_id(uid)
+    assign(socket, :shift_templates, user_shifts)
+  end
+
+  defp shift_template_from_params(params)
+
+  defp shift_template_from_params(%{"id" => id}),
+    do: ShiftTemplates.get_shift_template!(id)
+
+  defp shift_template_from_params(_params), do: %ShiftTemplate{}
+
+
   @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())}
+    {:noreply, assign_shift_templates(socket)}
   end
 
-  defp list_shift_templates do
-    ShiftTemplates.list_shift_templates()
+  @impl true
+  def handle_info({:close_modal, _}, %{assigns: %{modal_return_to: to}} = socket) do
+    socket |> copy_flash() |> push_patch(to: to) |> live_noreply()
   end
+
+  @impl true
+  def handle_info({:put_flash_message, {flash_type, msg}}, socket) do
+    socket |> put_flash(flash_type, msg) |> live_noreply()
+  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
index 6f92d575..3729b3e4 100644
--- a/lib/shift73k_web/live/shift_template_live/index.html.leex
+++ b/lib/shift73k_web/live/shift_template_live/index.html.leex
@@ -1,15 +1,24 @@
-<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) %>
+    current_user: @current_user %>
 <% end %>
 
-<table>
+
+<div class="d-flex justify-content-between d-flex align-items-center">
+  <h2>
+    <%= icon_div @socket, "bi-clock-history", [class: "icon baseline"] %>
+    My Shift Templates
+  </h2>
+  <%= live_patch "New Shift Template", to: Routes.shift_template_index_path(@socket, :new), class: "btn btn-primary" %>
+</div>
+
+
+<div class="table-responsive">
+<table class="table">
   <thead>
     <tr>
       <th>Label</th>
@@ -18,8 +27,7 @@
       <th>Location</th>
       <th>Timezone</th>
       <th>Start time</th>
-      <th>Length hours</th>
-      <th>Length minutes</th>
+      <th>Length</th>
 
       <th></th>
     </tr>
@@ -32,9 +40,8 @@
         <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><%= shift_template.start_time |> Calendar.strftime("%I:%M %p") %></td>
+        <td><%= shift_template.length_hours %>h <%= shift_template.length_minutes || 0 %>m</td>
 
         <td>
           <span><%= live_redirect "Show", to: Routes.shift_template_show_path(@socket, :show, shift_template) %></span>
@@ -45,5 +52,4 @@
     <% end %>
   </tbody>
 </table>
-
-<span><%= live_patch "New Shift template", to: Routes.shift_template_index_path(@socket, :new) %></span>
+</div>
diff --git a/lib/shift73k_web/roles.ex b/lib/shift73k_web/roles.ex
index 284730c0..ed8985b3 100644
--- a/lib/shift73k_web/roles.ex
+++ b/lib/shift73k_web/roles.ex
@@ -4,7 +4,7 @@ defmodule Shift73kWeb.Roles do
   """
 
   alias Shift73k.Accounts.User
-  # alias Shift73k.Properties.Property
+  alias Shift73k.ShiftTemplates.ShiftTemplate
 
   @type entity :: struct()
   @type action :: :new | :index | :edit | :show | :delete | :edit_role
@@ -12,13 +12,13 @@ defmodule Shift73kWeb.Roles do
 
   def can?(user, entity, action)
 
-  # # Properties / Property
-  # def can?(%User{role: :admin}, %Property{}, _any), do: true
-  # def can?(%User{}, %Property{}, :index), do: true
-  # def can?(%User{}, %Property{}, :new), do: true
-  # def can?(%User{}, %Property{}, :show), do: true
-  # def can?(%User{id: id}, %Property{user_id: id}, :edit), do: true
-  # def can?(%User{id: id}, %Property{user_id: id}, :delete), do: true
+  # ShiftTemplates / ShiftTemplate
+  def can?(%User{role: :admin}, %ShiftTemplate{}, _any), do: true
+  def can?(%User{}, %ShiftTemplate{}, :index), do: true
+  def can?(%User{}, %ShiftTemplate{}, :new), do: true
+  def can?(%User{}, %ShiftTemplate{}, :show), do: true
+  def can?(%User{id: id}, %ShiftTemplate{user_id: id}, :edit), do: true
+  def can?(%User{id: id}, %ShiftTemplate{user_id: id}, :delete), do: true
 
   # Accounts / User
   def can?(%User{role: :admin}, %User{}, _any), do: true
diff --git a/lib/shift73k_web/router.ex b/lib/shift73k_web/router.ex
index fb7798db..1f929c89 100644
--- a/lib/shift73k_web/router.ex
+++ b/lib/shift73k_web/router.ex
@@ -91,12 +91,12 @@ defmodule Shift73kWeb.Router do
   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 "/my_shifts", ShiftTemplateLive.Index, :index
+    live "/my_shifts/new", ShiftTemplateLive.Index, :new
+    live "/my_shifts/:id/edit", ShiftTemplateLive.Index, :edit
 
-    live "/shift_templates/:id", ShiftTemplateLive.Show, :show
-    live "/shift_templates/:id/show/edit", ShiftTemplateLive.Show, :edit
+    live "/my_shifts/:id", ShiftTemplateLive.Show, :show
+    live "/my_shifts/:id/show/edit", ShiftTemplateLive.Show, :edit
   end
 
   # scope "/", Shift73kWeb do
diff --git a/lib/shift73k_web/templates/layout/_navbar.html.eex b/lib/shift73k_web/templates/layout/_navbar.html.eex
index 431d6b8e..384487f0 100644
--- a/lib/shift73k_web/templates/layout/_navbar.html.eex
+++ b/lib/shift73k_web/templates/layout/_navbar.html.eex
@@ -3,7 +3,7 @@
 
     <h1 class="fs-4 my-0 py-0 lh-base">
     <%= link to: Routes.page_path(@conn, :index), class: "navbar-brand fs-4" do %>
-      <%= icon_div @conn, "mdi-skull-crossbones", [class: "icon baseline fs-3"] %>
+      <%= icon_div @conn, "bi-calendar3-week", [class: "icon baseline me-1"] %>
       <span class="fw-light">Shift73k</span>
     <% end %>
     </h1>