added Timex and refined shift template length handling
This commit is contained in:
parent
290475c101
commit
4fb0e2df7b
8 changed files with 67 additions and 86 deletions
|
@ -10,9 +10,6 @@ use Mix.Config
|
||||||
config :shift73k,
|
config :shift73k,
|
||||||
ecto_repos: [Shift73k.Repo]
|
ecto_repos: [Shift73k.Repo]
|
||||||
|
|
||||||
# Configure the time zone database
|
|
||||||
config :elixir, :time_zone_database, Tzdata.TimeZoneDatabase
|
|
||||||
|
|
||||||
# Custom application global variables
|
# Custom application global variables
|
||||||
config :shift73k, :app_global_vars,
|
config :shift73k, :app_global_vars,
|
||||||
time_zone: "America/New_York",
|
time_zone: "America/New_York",
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
defmodule Shift73k.Shifts.Templates.ShiftTemplate do
|
defmodule Shift73k.Shifts.Templates.ShiftTemplate do
|
||||||
|
use Timex
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
alias Shift73k.Shifts.Templates.ShiftTemplate
|
||||||
|
|
||||||
@app_vars Application.get_env(:shift73k, :app_global_vars, time_zone: "America/New_York")
|
@app_vars Application.get_env(:shift73k, :app_global_vars, time_zone: "America/New_York")
|
||||||
@time_zone @app_vars[:time_zone]
|
@time_zone @app_vars[:time_zone]
|
||||||
|
|
||||||
|
@ -42,45 +45,42 @@ defmodule Shift73k.Shifts.Templates.ShiftTemplate do
|
||||||
|> validate_length(:subject, count: :codepoints, max: 280)
|
|> validate_length(:subject, count: :codepoints, max: 280)
|
||||||
|> validate_length(:location, count: :codepoints, max: 280)
|
|> validate_length(:location, count: :codepoints, max: 280)
|
||||||
|> validate_change(:time_end, fn :time_end, time_end ->
|
|> validate_change(:time_end, fn :time_end, time_end ->
|
||||||
shift_length = shift_length(get_time_start(attrs), time_end)
|
shift_length = shift_length(time_end, time_start_from_attrs(attrs))
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
shift_length == 0 ->
|
shift_length == 0 ->
|
||||||
[time_end: "end time cannot equal start time"]
|
[time_end: "end time cannot equal start time"]
|
||||||
|
|
||||||
shift_length >= 16 * 3600 ->
|
shift_length >= 16 * 60 ->
|
||||||
[time_end: "you don't want to work 16 or more hours!"]
|
[time_end: "you don't want to work 16 or more hours!"]
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|> validate_inclusion(:time_zone, Tzdata.zone_list())
|
|> validate_inclusion(:time_zone, Timex.timezones())
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_time_start(%{"time_start" => time_start}), do: time_start
|
defp time_start_from_attrs(%{"time_start" => time_start}), do: time_start
|
||||||
defp get_time_start(%{time_start: time_start}), do: time_start
|
defp time_start_from_attrs(%{time_start: time_start}), do: time_start
|
||||||
defp get_time_start(_), do: nil
|
defp time_start_from_attrs(_), do: nil
|
||||||
|
|
||||||
def shift_length(time_start, time_end) do
|
def shift_length(%ShiftTemplate{time_end: time_end, time_start: time_start}) do
|
||||||
cond do
|
time_end
|
||||||
time_end > time_start ->
|
|> Timex.diff(time_start, :minute)
|
||||||
Time.diff(time_end, time_start)
|
|> shift_length()
|
||||||
|
|
||||||
time_start > time_end ->
|
|
||||||
len1 = Time.diff(~T[23:59:59], time_start) + 1
|
|
||||||
len2 = Time.diff(time_end, ~T[00:00:00])
|
|
||||||
len1 + len2
|
|
||||||
|
|
||||||
true ->
|
|
||||||
0
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def shift_length_h_m_tuple(time_start, time_end) do
|
def shift_length(len_min) when is_integer(len_min) and len_min >= 0, do: len_min
|
||||||
shift_length_seconds = shift_length(time_start, time_end)
|
def shift_length(len_min) when is_integer(len_min) and len_min < 0, do: 1440 + len_min
|
||||||
h = shift_length_seconds |> Integer.floor_div(3600)
|
|
||||||
m = shift_length_seconds |> rem(3600) |> Integer.floor_div(60)
|
def shift_length(time_end, time_start),
|
||||||
|
do: shift_length(%ShiftTemplate{time_end: time_end, time_start: time_start})
|
||||||
|
|
||||||
|
def shift_length_h_m(%ShiftTemplate{time_end: _, time_start: _} = template) do
|
||||||
|
shift_length_seconds = shift_length(template)
|
||||||
|
h = shift_length_seconds |> Integer.floor_div(60)
|
||||||
|
m = shift_length_seconds |> rem(60)
|
||||||
{h, m}
|
{h, m}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,49 +11,45 @@ defmodule Shift73kWeb.ShiftTemplateLive.FormComponent do
|
||||||
socket
|
socket
|
||||||
|> assign(assigns)
|
|> assign(assigns)
|
||||||
|> assign(:changeset, changeset)
|
|> assign(:changeset, changeset)
|
||||||
|> assign_shift_length(shift_template.time_start, shift_template.time_end)
|
|> assign_shift_length(shift_template)
|
||||||
|> live_okreply()
|
|> live_okreply()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp assign_shift_length(socket, time_start, time_end) do
|
defp assign_shift_length(socket, shift_template) do
|
||||||
shift_length = ShiftTemplate.shift_length_h_m_tuple(time_start, time_end)
|
shift_length = ShiftTemplate.shift_length_h_m(shift_template)
|
||||||
assign(socket, :shift_length, shift_length)
|
assign(socket, :shift_length, shift_length)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp prep_shift_template_params(shift_template_params, current_user) do
|
defp prep_template_params(params, current_user) do
|
||||||
time_start = Time.from_iso8601!("T#{shift_template_params["time_start"]}:00")
|
params
|
||||||
time_end = Time.from_iso8601!("T#{shift_template_params["time_end"]}:00")
|
|> Map.put("time_start", Time.from_iso8601!("T#{params["time_start"]}:00"))
|
||||||
|
|> Map.put("time_end", Time.from_iso8601!("T#{params["time_end"]}:00"))
|
||||||
shift_template_params
|
|
||||||
|> Map.put("time_start", time_start)
|
|
||||||
|> Map.put("time_end", time_end)
|
|
||||||
|> Map.put("user_id", current_user.id)
|
|> Map.put("user_id", current_user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_event("validate", %{"shift_template" => shift_template_params}, socket) do
|
def handle_event("validate", %{"shift_template" => params}, socket) do
|
||||||
shift_template_params =
|
params = prep_template_params(params, socket.assigns.current_user)
|
||||||
prep_shift_template_params(shift_template_params, socket.assigns.current_user)
|
|
||||||
|
|
||||||
changeset =
|
changeset =
|
||||||
socket.assigns.shift_template
|
socket.assigns.shift_template
|
||||||
|> Templates.change_shift_template(shift_template_params)
|
|> Templates.change_shift_template(params)
|
||||||
|> Map.put(:action, :validate)
|
|> Map.put(:action, :validate)
|
||||||
|
|
||||||
socket
|
socket
|
||||||
|> assign(:changeset, changeset)
|
|> assign(:changeset, changeset)
|
||||||
|> assign_shift_length(
|
|> assign_shift_length(%ShiftTemplate{
|
||||||
shift_template_params["time_start"],
|
time_end: params["time_end"],
|
||||||
shift_template_params["time_end"]
|
time_start: params["time_start"]
|
||||||
)
|
})
|
||||||
|> live_noreply()
|
|> live_noreply()
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_event("save", %{"shift_template" => shift_template_params}, socket) do
|
def handle_event("save", %{"shift_template" => params}, socket) do
|
||||||
save_shift_template(
|
save_shift_template(
|
||||||
socket,
|
socket,
|
||||||
socket.assigns.action,
|
socket.assigns.action,
|
||||||
prep_shift_template_params(shift_template_params, socket.assigns.current_user)
|
prep_template_params(params, socket.assigns.current_user)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -62,8 +58,8 @@ defmodule Shift73kWeb.ShiftTemplateLive.FormComponent do
|
||||||
{:noreply, push_event(socket, "modal-please-hide", %{})}
|
{:noreply, push_event(socket, "modal-please-hide", %{})}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp save_shift_template(socket, :new, shift_template_params) do
|
defp save_shift_template(socket, :new, params) do
|
||||||
case Templates.create_shift_template(shift_template_params) do
|
case Templates.create_shift_template(params) do
|
||||||
{:ok, _shift_template} ->
|
{:ok, _shift_template} ->
|
||||||
flash = {:info, "Shift template created successfully"}
|
flash = {:info, "Shift template created successfully"}
|
||||||
send(self(), {:put_flash_message, flash})
|
send(self(), {:put_flash_message, flash})
|
||||||
|
@ -77,15 +73,12 @@ defmodule Shift73kWeb.ShiftTemplateLive.FormComponent do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp save_shift_template(socket, :clone, shift_template_params) do
|
defp save_shift_template(socket, :clone, params) do
|
||||||
save_shift_template(socket, :new, shift_template_params)
|
save_shift_template(socket, :new, params)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp save_shift_template(socket, :edit, shift_template_params) do
|
defp save_shift_template(socket, :edit, params) do
|
||||||
case Templates.update_shift_template(
|
case Templates.update_shift_template(socket.assigns.shift_template, params) do
|
||||||
socket.assigns.shift_template,
|
|
||||||
shift_template_params
|
|
||||||
) do
|
|
||||||
{:ok, _shift_template} ->
|
{:ok, _shift_template} ->
|
||||||
flash = {:info, "Shift template updated successfully"}
|
flash = {:info, "Shift template updated successfully"}
|
||||||
send(self(), {:put_flash_message, flash})
|
send(self(), {:put_flash_message, flash})
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
list: "tz_list"
|
list: "tz_list"
|
||||||
%>
|
%>
|
||||||
<datalist id="tz_list">
|
<datalist id="tz_list">
|
||||||
<%= for tz_name <- Tzdata.zone_list() do %>
|
<%= for tz_name <- Timex.timezones() do %>
|
||||||
<option value="<%= tz_name %>"></option>
|
<option value="<%= tz_name %>"></option>
|
||||||
<% end %>
|
<% end %>
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,6 @@ defmodule Shift73kWeb.ShiftTemplateLive.Index do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def mount(_params, session, socket) do
|
def mount(_params, session, socket) do
|
||||||
# {:ok, assign(socket, :shift_templates, list_shift_templates())}
|
|
||||||
socket
|
socket
|
||||||
|> assign_defaults(session)
|
|> assign_defaults(session)
|
||||||
|> live_okreply()
|
|> live_okreply()
|
||||||
|
@ -97,14 +96,6 @@ defmodule Shift73kWeb.ShiftTemplateLive.Index do
|
||||||
|> live_noreply()
|
|> live_noreply()
|
||||||
end
|
end
|
||||||
|
|
||||||
# @impl true
|
|
||||||
# def handle_event("delete", %{"id" => id}, socket) do
|
|
||||||
# shift_template = Templates.get_shift_template!(id)
|
|
||||||
# {:ok, _} = Templates.delete_shift_template(shift_template)
|
|
||||||
|
|
||||||
# {:noreply, assign_shift_templates(socket)}
|
|
||||||
# end
|
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_info({:close_modal, _}, %{assigns: %{modal_return_to: to}} = socket) do
|
def handle_info({:close_modal, _}, %{assigns: %{modal_return_to: to}} = socket) do
|
||||||
socket |> copy_flash() |> push_patch(to: to) |> live_noreply()
|
socket |> copy_flash() |> push_patch(to: to) |> live_noreply()
|
||||||
|
|
|
@ -33,18 +33,18 @@
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<%= for shift <- @shift_templates do %>
|
<%= for template <- @shift_templates do %>
|
||||||
|
|
||||||
<div class="col-12 col-lg-6">
|
<div class="col-12 col-lg-6">
|
||||||
|
|
||||||
<div class="card mt-4">
|
<div class="card mt-4">
|
||||||
<h5 class="card-header d-flex justify-content-between align-items-start">
|
<h5 class="card-header d-flex justify-content-between align-items-start">
|
||||||
<div class="visually-hidden">Subject:</div>
|
<div class="visually-hidden">Subject:</div>
|
||||||
<%= shift.subject %>
|
<%= template.subject %>
|
||||||
<%= if shift.id == @current_user.fave_shift_template_id do %>
|
<%= if template.id == @current_user.fave_shift_template_id do %>
|
||||||
<%= icon_div @socket, "bi-star-fill", [class: "icon baseline text-primary align-self-start ms-2", phx_click: "unset-user-fave-shift-template"] %>
|
<%= icon_div @socket, "bi-star-fill", [class: "icon baseline text-primary align-self-start ms-2", phx_click: "unset-user-fave-shift-template"] %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= icon_div @socket, "bi-star", [class: "icon baseline text-primary align-self-start ms-2", phx_click: "set-user-fave-shift-template", phx_value_id: shift.id] %>
|
<%= icon_div @socket, "bi-star", [class: "icon baseline text-primary align-self-start ms-2", phx_click: "set-user-fave-shift-template", phx_value_id: template.id] %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</h5>
|
</h5>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
@ -57,15 +57,15 @@
|
||||||
<span class="visually-hidden">Hours:</span>
|
<span class="visually-hidden">Hours:</span>
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<%= shift.time_start |> Calendar.strftime("%I:%M%P") %>
|
<%= template.time_start |> Calendar.strftime("%I:%M%P") %>
|
||||||
—
|
—
|
||||||
<%= shift.time_end |> Calendar.strftime("%I:%M%P") %>
|
<%= template.time_end |> Calendar.strftime("%I:%M%P") %>
|
||||||
<span class="text-muted">
|
<span class="text-muted">
|
||||||
<span class="visually-hidden">Shift length:</span>
|
<span class="visually-hidden">Shift length:</span>
|
||||||
<% shift_length = ShiftTemplate.shift_length_h_m_tuple(shift.time_start, shift.time_end) %>
|
<% shift_len = ShiftTemplate.shift_length_h_m(template) %>
|
||||||
(<%= shift_length |> elem(0) %>h <%= shift_length |> elem(1) %>m)
|
(<%= shift_len |> elem(0) %>h <%= shift_len |> elem(1) %>m)
|
||||||
</span>
|
</span>
|
||||||
<span class="valid-feedback d-block text-muted mt-n1">TZ: <%= shift.time_zone %></span>
|
<span class="valid-feedback d-block text-muted mt-n1">TZ: <%= template.time_zone %></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
@ -75,8 +75,8 @@
|
||||||
<span class="visually-hidden">Location:</span>
|
<span class="visually-hidden">Location:</span>
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<%= if shift.location do %>
|
<%= if template.location do %>
|
||||||
<%= shift.location %>
|
<%= template.location %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span class="text-muted fst-italic">none</span>
|
<span class="text-muted fst-italic">none</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -88,8 +88,8 @@
|
||||||
<span class="visually-hidden">Description:</span>
|
<span class="visually-hidden">Description:</span>
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<%= if shift.description do %>
|
<%= if template.description do %>
|
||||||
<%= text_to_html shift.description %>
|
<%= text_to_html template.description %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span class="text-muted fst-italic">none</span>
|
<span class="text-muted fst-italic">none</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -98,15 +98,15 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<%= if Roles.can?(@current_user, shift, :edit) do %>
|
<%= if Roles.can?(@current_user, template, :edit) do %>
|
||||||
<%= live_patch to: Routes.shift_template_index_path(@socket, :edit, shift), class: "btn btn-primary btn-sm text-nowrap" 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", style: "margin-right:0.125rem;"] %>
|
<%= icon_div @socket, "bi-pencil", [class: "icon baseline", style: "margin-right:0.125rem;"] %>
|
||||||
Edit
|
Edit
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= if Roles.can?(@current_user, shift, :clone) do %>
|
<%= if Roles.can?(@current_user, template, :clone) do %>
|
||||||
<%= live_patch to: Routes.shift_template_index_path(@socket, :clone, shift), class: "btn btn-outline-primary btn-sm text-nowrap" do %>
|
<%= live_patch to: Routes.shift_template_index_path(@socket, :clone, template), class: "btn btn-outline-primary btn-sm text-nowrap" do %>
|
||||||
<%= icon_div @socket, "bi-clipboard-plus", [class: "icon baseline", style: "margin-right:0.125rem;"] %>
|
<%= icon_div @socket, "bi-clipboard-plus", [class: "icon baseline", style: "margin-right:0.125rem;"] %>
|
||||||
Clone
|
Clone
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -114,8 +114,8 @@
|
||||||
|
|
||||||
<%#= button "" %>
|
<%#= button "" %>
|
||||||
|
|
||||||
<%= if Roles.can?(@current_user, shift, :delete) do %>
|
<%= 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 %>">
|
<button class="btn btn-outline-danger btn-sm text-nowrap" phx-click="delete-modal" phx-value-id="<%= template.id %>">
|
||||||
<%= icon_div @socket, "bi-trash", [class: "icon baseline", style: "margin-right:0.125rem;"] %>
|
<%= icon_div @socket, "bi-trash", [class: "icon baseline", style: "margin-right:0.125rem;"] %>
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -52,7 +52,7 @@ defmodule Shift73k.MixProject do
|
||||||
{:bamboo, "~> 2.0"},
|
{:bamboo, "~> 2.0"},
|
||||||
{:bamboo_smtp, "~> 4.0"},
|
{:bamboo_smtp, "~> 4.0"},
|
||||||
{:scrivener_ecto, "~> 2.0"},
|
{:scrivener_ecto, "~> 2.0"},
|
||||||
{:tzdata, "~> 1.1"}
|
{:timex, "~> 3.6"}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ for user <- Accounts.list_users() do
|
||||||
subject: e["subject"],
|
subject: e["subject"],
|
||||||
description: e["description"],
|
description: e["description"],
|
||||||
location: e["location"],
|
location: e["location"],
|
||||||
time_zone: Tzdata.zone_list() |> Enum.random(),
|
time_zone: Timex.timezones() |> Enum.random(),
|
||||||
time_start: time_start,
|
time_start: time_start,
|
||||||
time_end: time_end,
|
time_end: time_end,
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
|
|
Loading…
Reference in a new issue