From 4c673508b59fbeff58cc7f37e8047cee5590ad22 Mon Sep 17 00:00:00 2001
From: Adam Piontek <adam@73k.us>
Date: Sun, 21 Mar 2021 19:27:25 -0400
Subject: [PATCH] some reorganization for inserting multiple shifts, setting up
 dev seeds

---
 lib/shift73k/repo.ex                          |  5 ++
 lib/shift73k/shifts.ex                        |  8 ++
 lib/shift73k/shifts/shift.ex                  | 19 ++---
 lib/shift73k/shifts/templates.ex              | 12 ++-
 .../shifts/templates/shift_template.ex        | 12 ++-
 .../live/shift_assign_live/index.ex           | 74 ++++++++-----------
 .../live/shift_template_live/index.ex         |  2 +-
 priv/repo/seeds.exs                           | 24 ++++++
 8 files changed, 95 insertions(+), 61 deletions(-)

diff --git a/lib/shift73k/repo.ex b/lib/shift73k/repo.ex
index 24add415..c817bf41 100644
--- a/lib/shift73k/repo.ex
+++ b/lib/shift73k/repo.ex
@@ -4,4 +4,9 @@ defmodule Shift73k.Repo do
     adapter: Ecto.Adapters.Postgres
 
   use Scrivener, page_size: 10
+
+  def timestamp(%{} = attrs) do
+    now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
+    Map.merge(attrs, %{inserted_at: now, updated_at: now})
+  end
 end
diff --git a/lib/shift73k/shifts.ex b/lib/shift73k/shifts.ex
index 8d6253d7..8d9c363b 100644
--- a/lib/shift73k/shifts.ex
+++ b/lib/shift73k/shifts.ex
@@ -87,6 +87,14 @@ defmodule Shift73k.Shifts do
     |> Repo.insert()
   end
 
+  def create_multiple(shift_attrs) when is_list(shift_attrs) do
+    try do
+      Repo.insert_all(Shift, shift_attrs)
+    rescue
+      e in Postgrex.Error -> {:error, e.message}
+    end
+  end
+
   @doc """
   Updates a shift.
 
diff --git a/lib/shift73k/shifts/shift.ex b/lib/shift73k/shifts/shift.ex
index dfc00279..0e7b7481 100644
--- a/lib/shift73k/shifts/shift.ex
+++ b/lib/shift73k/shifts/shift.ex
@@ -2,6 +2,8 @@ defmodule Shift73k.Shifts.Shift do
   use Ecto.Schema
   import Ecto.Changeset
 
+  alias Shift73k.Shifts.Templates.ShiftTemplate
+
   @primary_key {:id, :binary_id, autogenerate: true}
   @foreign_key_type :binary_id
   schema "shifts" do
@@ -31,14 +33,13 @@ defmodule Shift73k.Shifts.Shift do
       :time_end,
       :user_id
     ])
-
-    # |> validate_required([
-    #   :subject,
-    #   :date,
-    #   :time_zone,
-    #   :time_start,
-    #   :time_end,
-    #   :user_id
-    # ])
+    |> validate_required([
+      :subject,
+      :date,
+      :time_zone,
+      :time_start,
+      :time_end,
+      :user_id
+    ])
   end
 end
diff --git a/lib/shift73k/shifts/templates.ex b/lib/shift73k/shifts/templates.ex
index 6530802f..b5cac767 100644
--- a/lib/shift73k/shifts/templates.ex
+++ b/lib/shift73k/shifts/templates.ex
@@ -21,13 +21,11 @@ defmodule Shift73k.Shifts.Templates do
     Repo.all(ShiftTemplate)
   end
 
-  def list_shift_templates_by_user_id(user_id) do
-    q =
-      from s in ShiftTemplate,
-        where: s.user_id == ^user_id,
-        order_by: [fragment("lower(?)", s.subject), s.time_start]
-
-    Repo.all(q)
+  def list_shift_templates_by_user(user_id) do
+    from(s in ShiftTemplate)
+    |> where([s], s.user_id == ^user_id)
+    |> order_by([s], [fragment("lower(?)", s.subject), s.time_start])
+    |> Repo.all()
   end
 
   @doc """
diff --git a/lib/shift73k/shifts/templates/shift_template.ex b/lib/shift73k/shifts/templates/shift_template.ex
index bfa64d62..b44c64dc 100644
--- a/lib/shift73k/shifts/templates/shift_template.ex
+++ b/lib/shift73k/shifts/templates/shift_template.ex
@@ -77,6 +77,14 @@ defmodule Shift73k.Shifts.Templates.ShiftTemplate do
   def shift_length(len_min) when is_integer(len_min) and len_min >= 0, do: len_min
   def shift_length(len_min) when is_integer(len_min) and len_min < 0, do: 1440 + len_min
 
-  def shift_length(time_end, time_start),
-    do: shift_length(%ShiftTemplate{time_end: time_end, time_start: time_start})
+  def shift_length(time_end, time_start) do
+    shift_length(%ShiftTemplate{time_end: time_end, time_start: time_start})
+  end
+
+  # Get shift attrs from shift template
+  def attrs(%ShiftTemplate{} = shift_template) do
+    shift_template
+    |> Map.from_struct()
+    |> Map.drop([:__meta__, :id, :inserted_at, :updated_at, :user, :is_fave_of_user])
+  end
 end
diff --git a/lib/shift73k_web/live/shift_assign_live/index.ex b/lib/shift73k_web/live/shift_assign_live/index.ex
index 0b5ccb0b..5e8e08ab 100644
--- a/lib/shift73k_web/live/shift_assign_live/index.ex
+++ b/lib/shift73k_web/live/shift_assign_live/index.ex
@@ -81,7 +81,7 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
 
   defp init_shift_templates(%{assigns: %{current_user: user}} = socket) do
     shift_templates =
-      Templates.list_shift_templates_by_user_id(user.id)
+      Templates.list_shift_templates_by_user(user.id)
       |> Stream.map(fn t -> shift_template_option(t, user.fave_shift_template_id) end)
       |> Enum.concat([@custom_shift_opt])
 
@@ -252,12 +252,7 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
 
   @impl true
   def handle_event("select-day", %{"day" => day}, socket) do
-    selected_days =
-      case Enum.member?(socket.assigns.selected_days, day) do
-        false -> [day | socket.assigns.selected_days]
-        true -> Enum.reject(socket.assigns.selected_days, fn d -> d == day end)
-      end
-
+    selected_days = update_selected_days(socket.assigns.selected_days, day)
     {:noreply, assign(socket, :selected_days, selected_days)}
   end
 
@@ -277,17 +272,15 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
   @impl true
   def handle_event("save-days", _params, socket) do
     # 1. collect attrs from loaded shift template
-    shift_data = shift_data_from_template(socket.assigns.shift_template)
+    shift_data = ShiftTemplate.attrs(socket.assigns.shift_template)
 
-    # 2. create list of shift attrs to insert
-    to_insert =
-      Enum.map(socket.assigns.selected_days, &shift_from_day_and_shift_data(&1, shift_data))
-
-    # 3. insert the data
-    {status, msg} = insert_shifts(to_insert, length(socket.assigns.selected_days))
-
-    socket
-    |> put_flash(status, msg)
+    # 2. fashion list of shift attrs and insert
+    socket.assigns.selected_days
+    |> Stream.map(&Date.from_iso8601!/1)
+    |> Stream.map(&Map.put(shift_data, :date, &1))
+    |> Enum.map(&Repo.timestamp/1)
+    |> Shifts.create_multiple()
+    |> handle_create_multiple_result(socket)
     |> assign(:selected_days, [])
     |> assign_known_shifts()
     |> live_noreply()
@@ -320,35 +313,25 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
     |> live_noreply()
   end
 
-  defp shift_data_from_template(shift_template) do
-    shift_template
-    |> Map.from_struct()
-    |> Map.drop([:__meta__, :id, :inserted_at, :updated_at, :user, :is_fave_of_user])
-  end
+  defp handle_create_multiple_result(result, socket) do
+    day_count = length(socket.assigns.selected_days)
 
-  defp shift_from_day_and_shift_data(day, shift_data) do
-    now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
-    date_data = %{date: Date.from_iso8601!(day), inserted_at: now, updated_at: now}
-    Map.merge(shift_data, date_data)
-  end
+    {status, msg} =
+      case result do
+        {:error, errmsg} ->
+          {:error, "Ope, problem error inserting shifts, page the dev! Message: #{errmsg}"}
 
-  defp insert_shifts(to_insert, day_count) do
-    Multi.new()
-    |> Multi.insert_all(:insert_all, Shift, to_insert)
-    |> Repo.transaction()
-    |> case do
-      {:ok, %{insert_all: {n, _}}} ->
-        s = (n > 1 && "s") || ""
+        {n, _} ->
+          s = (n > 1 && "s") || ""
 
-        if n == day_count do
-          {:success, "Successfully assigned shift to #{n} day#{s}"}
-        else
-          {:warning, "Some error, only #{n} day#{s} inserted but #{day_count} were selected"}
-        end
+          if n == day_count do
+            {:success, "Successfully assigned shift to #{n} day#{s}"}
+          else
+            {:warning, "Some error, only #{n} day#{s} inserted but #{day_count} were selected"}
+          end
+      end
 
-      _ ->
-        {:error, "Ope, unknown error inserting shifts, page the dev"}
-    end
+    put_flash(socket, status, msg)
   end
 
   def shifts_to_show(day_shifts) do
@@ -356,4 +339,11 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
       do: Enum.take(day_shifts, 1),
       else: day_shifts
   end
+
+  defp update_selected_days(selected_days, day) do
+    case Enum.member?(selected_days, day) do
+      false -> [day | selected_days]
+      true -> Enum.reject(selected_days, fn d -> d == day end)
+    end
+  end
 end
diff --git a/lib/shift73k_web/live/shift_template_live/index.ex b/lib/shift73k_web/live/shift_template_live/index.ex
index aafc8332..8cea1922 100644
--- a/lib/shift73k_web/live/shift_template_live/index.ex
+++ b/lib/shift73k_web/live/shift_template_live/index.ex
@@ -65,7 +65,7 @@ defmodule Shift73kWeb.ShiftTemplateLive.Index do
 
   defp assign_shift_templates(socket) do
     %User{id: uid} = socket.assigns.current_user
-    user_shifts = Templates.list_shift_templates_by_user_id(uid)
+    user_shifts = Templates.list_shift_templates_by_user(uid)
     assign(socket, :shift_templates, user_shifts)
   end
 
diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs
index 916f876e..d99cbe5e 100644
--- a/priv/repo/seeds.exs
+++ b/priv/repo/seeds.exs
@@ -121,3 +121,27 @@ for user <- Accounts.list_users() do
 
   Repo.insert_all(ShiftTemplate, user_shifts)
 end
+
+#####
+# insert shifts for each user?
+alias Shift73k.Shifts
+alias Shift73k.Shifts.Templates
+
+for user <- Accounts.list_users() do
+  # build a date range for the time from 120 days ago to 120 days from now
+  today = Date.utc_today()
+  date_range = Date.range(Date.add(today, -120), Date.add(today, 120))
+
+  # get 3 random shift templates for user
+  st_list = Templates.list_shift_templates_by_user(user.id) |> Enum.take_random(3)
+
+  for st <- st_list do
+    days_to_schedule = Enum.take_random(date_range, 47)
+    shift_data = ShiftTemplate.attrs(st)
+
+    days_to_schedule
+    |> Stream.map(&Map.put(shift_data, :date, &1))
+    |> Enum.map(&Repo.timestamp/1)
+    |> Shifts.create_multiple()
+  end
+end