shift73k/lib/shift73k_web/live/shift_assign_live/index.ex

360 lines
10 KiB
Elixir
Raw Normal View History

defmodule Shift73kWeb.ShiftAssignLive.Index do
use Shift73kWeb, :live_view
2021-03-16 11:00:33 -04:00
alias Ecto.Multi
alias Shift73k.Repo
alias Shift73k.Shifts
alias Shift73k.Shifts.Shift
2021-03-15 15:46:59 -04:00
alias Shift73k.Shifts.Templates
alias Shift73k.Shifts.Templates.ShiftTemplate
@custom_shift %ShiftTemplate{subject: "Custom shift", id: "custom-shift"}
@custom_shift_opt {@custom_shift.subject, @custom_shift.id}
@impl true
def mount(_params, session, socket) do
socket
|> assign_defaults(session)
2021-03-15 15:46:59 -04:00
|> assign(:custom_shift, @custom_shift)
|> assign(:show_template_btn_active, false)
|> assign(:show_template_details, false)
2021-03-15 15:46:59 -04:00
|> assign(:selected_days, [])
|> assign(:delete_days_shifts, nil)
|> live_okreply()
end
2021-03-15 15:46:59 -04:00
@impl true
def handle_params(_params, _url, socket) do
socket
|> init_shift_templates()
|> init_shift_template()
|> show_details_if_custom()
|> assign_shift_length()
|> assign_shift_template_changeset()
|> assign_modal_close_handlers()
|> init_today(Date.utc_today())
|> init_day_names()
2021-03-20 12:45:50 -04:00
|> update_calendar()
2021-03-15 15:46:59 -04:00
|> live_noreply()
end
defp assign_modal_close_handlers(socket) do
to = Routes.shift_assign_index_path(socket, :index)
assign(socket, modal_return_to: to, modal_close_action: :return)
end
2021-03-15 15:46:59 -04:00
defp get_shift_template("custom-shift"), do: @custom_shift
defp get_shift_template(template_id), do: Templates.get_shift_template(template_id)
defp assign_shift_length(%{assigns: %{shift_template: shift}} = socket) do
assign(socket, :shift_length, format_shift_length(shift))
end
2021-03-20 12:45:50 -04:00
defp assign_known_shifts(%{assigns: %{current_user: user}} = socket) do
date_range = socket.assigns.date_range
known_shifts = Shifts.list_shifts_by_user_in_date_range(user.id, date_range)
2021-03-16 11:00:33 -04:00
assign(socket, :known_shifts, known_shifts)
2021-03-15 15:46:59 -04:00
end
defp init_today(socket, today) do
assign(socket, current_date: today, cursor_date: cursor_date(today))
end
defp cursor_date(%Date{} = date) do
date |> Date.beginning_of_month() |> Date.add(4)
2021-03-15 15:46:59 -04:00
end
defp assign_shift_template_changeset(%{assigns: %{shift_template: shift}} = socket) do
cs = Templates.change_shift_template(shift)
assign(socket, :shift_template_changeset, cs)
end
defp init_shift_template(socket) do
first_list_id = socket.assigns.shift_templates |> hd() |> elem(1)
fave_id = socket.assigns.current_user.fave_shift_template_id
assign_shift_template(socket, fave_id || first_list_id)
2021-03-15 15:46:59 -04:00
end
defp assign_shift_template(socket, template_id) do
assign(socket, :shift_template, get_shift_template(template_id))
end
defp init_shift_templates(%{assigns: %{current_user: user}} = socket) do
shift_templates =
Templates.list_shift_templates_by_user_id(user.id)
2021-03-20 12:45:50 -04:00
|> Stream.map(fn t -> shift_template_option(t, user.fave_shift_template_id) end)
2021-03-15 15:46:59 -04:00
|> Enum.concat([@custom_shift_opt])
2021-03-15 15:46:59 -04:00
assign(socket, :shift_templates, shift_templates)
end
defp shift_template_option(template, fave_id) do
label =
template.subject <>
" (" <>
format_shift_time(template.time_start) <>
"" <>
format_shift_time(template.time_end) <> ")"
2021-03-15 15:46:59 -04:00
label =
case fave_id == template.id do
true -> label <> ""
false -> label
end
{label, template.id}
end
defp init_day_names(%{assigns: %{current_user: user, current_date: today}} = socket) do
week_start = Date.beginning_of_week(today, user.week_start_at)
day_names =
week_start
|> Date.range(Date.add(week_start, 6))
|> Enum.map(&Calendar.strftime(&1, "%a"))
assign(socket, :day_names, day_names)
end
2021-03-20 12:45:50 -04:00
defp date_range(cursor_date, week_start_at) do
last =
cursor_date
|> Date.end_of_month()
|> Date.end_of_week(week_start_at)
2021-03-20 12:45:50 -04:00
cursor_date
|> Date.beginning_of_month()
|> Date.beginning_of_week(week_start_at)
2021-03-20 12:45:50 -04:00
|> Date.range(last)
end
2021-03-20 12:45:50 -04:00
defp assign_date_range(%{assigns: %{current_user: user}} = socket) do
date_range = date_range(socket.assigns.cursor_date, user.week_start_at)
assign(socket, :date_range, date_range)
end
defp assign_week_rows(%{assigns: %{date_range: date_range}} = socket) do
assign(socket, :week_rows, Enum.chunk_every(date_range, 7))
end
2021-03-15 15:46:59 -04:00
def day_color(day, current_date, cursor_date, selected_days) do
cond do
Enum.member?(selected_days, Date.to_string(day)) ->
cond do
Date.compare(day, current_date) == :eq -> "bg-triangle-info text-white"
2021-03-15 15:46:59 -04:00
day.month != cursor_date.month -> "bg-triangle-light text-gray"
true -> "bg-triangle-white"
end
Date.compare(day, current_date) == :eq ->
"bg-info text-white"
2021-03-15 15:46:59 -04:00
day.month != cursor_date.month ->
"bg-light text-gray"
2021-03-15 15:46:59 -04:00
true ->
""
2021-03-15 15:46:59 -04:00
end
end
2021-03-15 15:46:59 -04:00
defp prep_template_params(params, current_user) do
params
|> Map.put("time_start", Time.from_iso8601!("T#{params["time_start"]}:00"))
|> Map.put("time_end", Time.from_iso8601!("T#{params["time_end"]}:00"))
|> Map.put("user_id", current_user.id)
end
2021-03-15 15:46:59 -04:00
defp show_details_if_custom(socket) do
if socket.assigns.shift_template.id != @custom_shift.id ||
socket.assigns.show_template_details do
2021-03-15 15:46:59 -04:00
socket
else
socket
|> assign(:show_template_btn_active, true)
2021-03-15 15:46:59 -04:00
|> push_event("toggle-template-details", %{targetId: "#templateDetailsCol"})
end
end
2021-03-20 12:45:50 -04:00
defp update_calendar(socket) do
socket
|> assign_date_range()
|> assign_week_rows()
|> assign_known_shifts()
end
2021-03-15 15:46:59 -04:00
@impl true
def handle_event("validate-shift-template", %{"shift_template" => params}, socket) do
params = prep_template_params(params, socket.assigns.current_user)
shift_template = socket.assigns.shift_template
2021-03-15 15:46:59 -04:00
cs =
shift_template
|> Templates.change_shift_template(params)
|> Map.put(:action, :validate)
socket
|> assign(:shift_template_changeset, cs)
|> assign(:shift_template, Map.merge(shift_template, cs.changes))
|> assign_shift_length()
|> live_noreply()
end
@impl true
def handle_event(
"change-selected-template",
%{"template_select" => %{"template" => template_id}},
socket
) do
2021-03-15 15:46:59 -04:00
socket
|> assign_shift_template(template_id)
|> show_details_if_custom()
|> assign_shift_length()
|> assign_shift_template_changeset()
|> live_noreply()
end
@impl true
def handle_event("month-nav", %{"month" => nav}, socket) do
2021-03-15 15:46:59 -04:00
new_cursor =
cond do
nav == "now" ->
Date.utc_today()
2021-03-15 15:46:59 -04:00
true ->
socket.assigns.cursor_date
|> Date.add((nav == "prev" && -30) || 30)
|> cursor_date()
2021-03-15 15:46:59 -04:00
end
2021-03-20 12:45:50 -04:00
socket
|> assign(:cursor_date, new_cursor)
|> update_calendar()
|> live_noreply()
2021-03-15 15:46:59 -04:00
end
@impl true
def handle_event("toggle-template-details", %{"target_id" => target_id}, socket) do
socket
|> assign(:show_template_btn_active, !socket.assigns.show_template_btn_active)
|> push_event("toggle-template-details", %{targetId: target_id})
|> live_noreply()
end
@impl true
def handle_event("collapse-shown", %{"target_id" => _target_id}, socket) do
{:noreply, assign(socket, :show_template_details, true)}
2021-03-15 15:46:59 -04:00
end
@impl true
def handle_event("collapse-hidden", %{"target_id" => _target_id}, socket) do
{:noreply, assign(socket, :show_template_details, false)}
2021-03-15 15:46:59 -04:00
end
@impl true
def handle_event("select-day", %{"day" => day}, socket) do
selected_days =
2021-03-20 12:45:50 -04:00
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)
2021-03-15 15:46:59 -04:00
end
{:noreply, assign(socket, :selected_days, selected_days)}
end
@impl true
def handle_event("delete-days-shifts", _params, socket) do
socket
|> assign(:modal_close_action, :delete_days_shifts)
|> assign(:delete_days_shifts, socket.assigns.selected_days)
|> live_noreply()
end
2021-03-15 15:46:59 -04:00
@impl true
def handle_event("clear-days", _params, socket) do
{:noreply, assign(socket, :selected_days, [])}
end
2021-03-16 11:00:33 -04:00
@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)
# 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))
2021-03-16 11:00:33 -04:00
# 3. insert the data
{status, msg} = insert_shifts(to_insert, length(socket.assigns.selected_days))
socket
|> put_flash(status, msg)
|> assign(:selected_days, [])
|> assign_known_shifts()
|> 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
@impl true
def handle_info({:clear_selected_days, _}, socket) do
socket |> assign(:selected_days, []) |> live_noreply()
end
@impl true
def handle_info({:close_modal, _}, %{assigns: %{modal_close_action: :return}} = socket) do
socket
|> copy_flash()
|> push_patch(to: socket.assigns.modal_return_to)
|> live_noreply()
end
@impl true
def handle_info({:close_modal, _}, %{assigns: %{modal_close_action: assign_key}} = socket) do
socket
|> assign(assign_key, nil)
|> assign_modal_close_handlers()
|> assign_known_shifts()
|> live_noreply()
end
2021-03-16 11:00:33 -04:00
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])
2021-03-16 11:00:33 -04:00
end
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
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") || ""
2021-03-16 11:00:33 -04:00
if n == day_count do
{:success, "Successfully assigned shift to #{n} day#{s}"}
2021-03-16 11:00:33 -04:00
else
{:warning, "Some error, only #{n} day#{s} inserted but #{day_count} were selected"}
2021-03-16 11:00:33 -04:00
end
_ ->
{:error, "Ope, unknown error inserting shifts, page the dev"}
2021-03-16 11:00:33 -04:00
end
end
def shifts_to_show(day_shifts) do
if length(day_shifts) == 1 || length(day_shifts) > 2,
do: Enum.take(day_shifts, 1),
else: day_shifts
end
end