diff --git a/lib/shift73k/shifts.ex b/lib/shift73k/shifts.ex index 6e92438f..1ccc8672 100644 --- a/lib/shift73k/shifts.ex +++ b/lib/shift73k/shifts.ex @@ -86,8 +86,12 @@ defmodule Shift73k.Shifts do ** (Ecto.NoResultsError) """ + def get_shift!(nil), do: nil def get_shift!(id), do: Repo.get!(Shift, id) + def get_shift(nil), do: nil + def get_shift(id), do: Repo.get(Shift, id) + @doc """ Creates a shift. diff --git a/lib/shift73k_web/live/shift_live/delete_component.ex b/lib/shift73k_web/live/shift_live/delete_component.ex new file mode 100644 index 00000000..05c41f0c --- /dev/null +++ b/lib/shift73k_web/live/shift_live/delete_component.ex @@ -0,0 +1,46 @@ +defmodule Shift73kWeb.ShiftLive.DeleteComponent do + use Shift73kWeb, :live_component + + alias Shift73k.Shifts + + @impl true + def update(assigns, socket) do + socket + |> assign(assigns) + |> live_okreply() + end + + @impl true + def handle_event("confirm", %{"id" => id, "subject" => subject, "datetime" => datetime}, socket) do + shift = Shifts.get_shift(id) + + if (shift) do + shift + |> Shifts.delete_shift() + |> case do + {:ok, _} -> + flash = {:info, "Shift deleted successfully: \"#{subject}\""} + send(self(), {:put_flash_message, flash}) + + socket + |> push_event("modal-please-hide", %{}) + |> live_noreply() + + {:error, _} -> + handle_error(socket, subject, datetime) + end + end + end + + defp handle_error(socket, subject, datetime) do + flash = + {:error, + "Some error trying to delete shift \"#{subject} (#{datetime})\". Possibly already deleted? Reloading list..."} + + send(self(), {:put_flash_message, flash}) + + socket + |> push_event("modal-please-hide", %{}) + |> live_noreply() + end +end diff --git a/lib/shift73k_web/live/shift_live/delete_component.html.heex b/lib/shift73k_web/live/shift_live/delete_component.html.heex new file mode 100644 index 00000000..45b5d332 --- /dev/null +++ b/lib/shift73k_web/live/shift_live/delete_component.html.heex @@ -0,0 +1,22 @@ +<div> + + <div class="modal-body"> + <% shift_datetime = "#{Calendar.strftime(@delete_shift.date, "%A, %b %-d")}, #{format_shift_time(@delete_shift.time_start)} — #{format_shift_time(@delete_shift.time_end)}" %> + + Are you sure you want to delete "<%= @delete_shift.subject %> (<%= shift_datetime %>)?" + + </div> + <div class="modal-footer"> + + <%= link "Cancel", to: "#", class: "btn btn-outline-dark", phx_click: "hide", phx_target: "##{@modal_id}" %> + <%= link "Confirm Delete", to: "#", + class: "btn btn-danger", + phx_click: "confirm", + phx_target: @myself, + phx_value_id: @delete_shift.id, + phx_value_subject: @delete_shift.subject, + phx_value_datetime: shift_datetime %> + + </div> + +</div> diff --git a/lib/shift73k_web/live/shift_live/index.ex b/lib/shift73k_web/live/shift_live/index.ex index 36372328..19fe63d8 100644 --- a/lib/shift73k_web/live/shift_live/index.ex +++ b/lib/shift73k_web/live/shift_live/index.ex @@ -22,6 +22,7 @@ defmodule Shift73kWeb.ShiftLive.Index do socket |> init_today(Date.utc_today()) |> update_agenda() + |> assign_modal_close_handlers() |> assign(:delete_shift, nil) |> apply_action(socket.assigns.live_action, params) |> live_noreply() @@ -33,6 +34,11 @@ defmodule Shift73kWeb.ShiftLive.Index do end end + defp assign_modal_close_handlers(socket) do + to = Routes.shift_index_path(socket, :index) + assign(socket, modal_return_to: to, modal_close_action: :return) + end + defp apply_action(socket, :index, _params) do socket |> assign(:page_title, "My Shifts") @@ -76,6 +82,14 @@ defmodule Shift73kWeb.ShiftLive.Index do |> assign_known_shifts() end + @impl true + def handle_event("delete-modal", %{"id" => id}, socket) do + socket + |> assign(:modal_close_action, :delete_shift) + |> assign(:delete_shift, Shifts.get_shift!(id)) + |> live_noreply() + end + @impl true def handle_event("delete", %{"id" => id}, socket) do shift = Shifts.get_shift!(id) @@ -94,6 +108,28 @@ defmodule Shift73kWeb.ShiftLive.Index do |> 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 + + @impl true + def handle_info({:put_flash_message, {flash_type, msg}}, socket) do + socket |> put_flash(flash_type, msg) |> live_noreply() + end + defp new_nav_cursor("now", _cursor_date), do: Date.utc_today() defp new_nav_cursor(nav, cursor_date) do diff --git a/lib/shift73k_web/live/shift_live/index.html.leex b/lib/shift73k_web/live/shift_live/index.html.heex similarity index 65% rename from lib/shift73k_web/live/shift_live/index.html.leex rename to lib/shift73k_web/live/shift_live/index.html.heex index 5e0191e4..bc9cdf08 100644 --- a/lib/shift73k_web/live/shift_live/index.html.leex +++ b/lib/shift73k_web/live/shift_live/index.html.heex @@ -1,40 +1,42 @@ +<%= if @delete_shift do %> + <%= live_modal @socket, Shift73kWeb.ShiftLive.DeleteComponent, + id: @delete_shift.id, + title: "Delete Shift Template", + delete_shift: @delete_shift %> +<% end %> + + <div class="row justify-content-start justify-content-sm-center"> <div class="col-md-10 col-xl-10"> <h2 class="mb-3 mb-sm-0"> - <%= icon_div @socket, "bi-card-list", [class: "icon baseline"] %> - My Shifts + <i class="bi bi-card-list me-1"></i> My Shifts </h2> - - - <div class="row justify-content-start justify-content-sm-center"> <div class="col-md-10 col-xl-10"> - <%# month navigation %> <div class="d-flex justify-content-between align-items-end my-4"> <h3 class="text-muted mb-0"> <%= Calendar.strftime(@cursor_date, "%B %Y") %> </h3> <div> - <button type="button" phx-click="month-nav" phx-value-month="now" class="btn btn-info text-white" <%= if Map.get(@cursor_date, :month) == Map.get(Date.utc_today(), :month), do: "disabled" %>> - <%= icon_div @socket, "bi-asterisk", [class: "icon baseline"] %> + <button type="button" phx-click="month-nav" phx-value-month="now" class="btn btn-info text-white" disabled={if Map.get(@cursor_date, :month) == Map.get(Date.utc_today(), :month), do: :true, else: :false}> + <i class="bi bi-asterisk me-sm-1"></i> <span class="d-none d-sm-inline">Today</span> </button> <button type="button" phx-click="month-nav" phx-value-month="prev" class="btn btn-primary"> - <%= icon_div @socket, "bi-chevron-left", [class: "icon baseline"] %> + <i class="bi bi-chevron-left me-sm-1"></i> <span class="d-none d-sm-inline">Prev</span> </button> <button type="button" phx-click="month-nav" phx-value-month="next" class="btn btn-primary"> <span class="d-none d-sm-inline">Next</span> - <%= icon_div @socket, "bi-chevron-right", [class: "icon baseline", style: "margin-left:0.125rem;"] %> + <i class="bi bi-chevron-right ms-sm-1"></i> </button> </div> </div> - <%= for day <- Enum.to_list(@date_range) do %> <%= if Date.day_of_week(day, @current_user.week_start_at) == 1 do %> <div class="border-top mt-4 mb-4"></div> @@ -45,24 +47,21 @@ <% day_shifts = Enum.filter(@shifts, fn s -> s.date == day end) %> <%= if !Enum.empty?(day_shifts) do %> - <%= for shift <- day_shifts do %> - - <div class="card mt-2 mb-4 col-12 ms-sm-3 ms-md-4 col-lg-10 ms-lg-5 col-xxl-8" id="shift-<%= shift.id %>"> + <div class="card mt-2 mb-4 col-12 ms-sm-3 ms-md-4 col-lg-10 ms-lg-5 col-xxl-8" id={"shift-#{shift.id}"}> <div class="card-body"> <h5 class="card-title"> - <%= icon_div @socket, "bi-tag", [class: "icon baseline text-muted me-1"] %> + <i class="bi bi-tag text-muted me-1"></i> <%= shift.subject %> </h5> - <table class="table table-borderless table-nonfluid table-sm"> <tbody> <tr> <th scope="row" class="text-end"> - <%= icon_div @socket, "bi-hourglass", [class: "icon baseline text-muted"] %> + <i class="bi bi-hourglass text-muted"></i> <span class="visually-hidden">Hours:</span> </th> <td> @@ -79,7 +78,7 @@ <tr> <th scope="row" class="text-end"> - <%= icon_div @socket, "bi-geo", [class: "icon baseline text-muted"] %> + <i class="bi bi-geo text-muted"></i> <span class="visually-hidden">Location:</span> </th> <td> @@ -92,7 +91,7 @@ </tr> <tr> <th scope="row" class="text-end"> - <%= icon_div @socket, "bi-justify-left", [class: "icon baseline text-muted"] %> + <i class="bi bi-justify-left text-muted"></i> <span class="visually-hidden">Description:</span> </th> <td class="shift-description"> @@ -106,51 +105,22 @@ </tbody> </table> - <%#= if Roles.can?(@current_user, template, :edit) do %> - <%#= live_patch to: Routes.shift_template_index_path(@socket, :edit, template), class: "btn btn-primary btn-sm text-nowrap" do %> - <%#= icon_div @socket, "bi-pencil", [class: "icon baseline"] %> - <%# Edit %> - <%# end %> - <%# end %> - - <%#= if Roles.can?(@current_user, template, :delete) do %> - <%# <button class="btn btn-outline-danger btn-sm text-nowrap" phx-click="delete-modal" phx-value-id=" %> - <%#= shift.id %> - <%# "> %> - <%#= icon_div @socket, "bi-trash", [class: "icon baseline"] %> - <%# Delete %> - <%# </button> %> - <%# end %> - - <%= button to: "#", phx_click: "delete", phx_value_id: shift.id, data: [confirm: "Are you sure?"], class: "btn btn-outline-danger btn-sm text-nowrap" do %> - <%= icon_div @socket, "bi-trash", [class: "icon baseline"] %> - Delete - <% end %> - - + <button class="btn btn-outline-danger btn-sm text-nowrap" phx-click="delete-modal" phx-value-id={shift.id}> + <i class="bi bi-trash me-1"></i> Delete + </button> </div> </div> - - - <% end %> - - - - - <% else %> <p class="text-muted"><em>Nothing scheduled</em></p> <% end %> <% end %> - </div> </div> - </div> </div>