improvements including removing Timex library

This commit is contained in:
Adam Piontek 2021-03-21 10:47:53 -04:00
parent ab11131df6
commit 686db55e8b
18 changed files with 179 additions and 149 deletions

View file

@ -7,6 +7,8 @@
# General application configuration # General application configuration
use Mix.Config use Mix.Config
config :elixir, :time_zone_database, Tzdata.TimeZoneDatabase
config :shift73k, config :shift73k,
ecto_repos: [Shift73k.Repo] ecto_repos: [Shift73k.Repo]

View file

@ -26,8 +26,15 @@ defmodule Shift73k.Shifts do
|> where([s], s.user_id == ^user_id) |> where([s], s.user_id == ^user_id)
end end
def list_shifts_by_user(user_id) do
user_id
|> query_shifts_by_user()
|> Repo.all()
end
def list_shifts_by_user_in_date_range(user_id, %Date.Range{} = date_range) do def list_shifts_by_user_in_date_range(user_id, %Date.Range{} = date_range) do
query_shifts_by_user(user_id) user_id
|> query_shifts_by_user()
|> where([s], s.date >= ^date_range.first) |> where([s], s.date >= ^date_range.first)
|> where([s], s.date <= ^date_range.last) |> where([s], s.date <= ^date_range.last)
|> order_by([s], [s.date, s.time_start]) |> order_by([s], [s.date, s.time_start])
@ -35,12 +42,14 @@ defmodule Shift73k.Shifts do
end end
defp query_shifts_by_user_from_list_of_dates(user_id, date_list) do defp query_shifts_by_user_from_list_of_dates(user_id, date_list) do
query_shifts_by_user(user_id) user_id
|> query_shifts_by_user()
|> where([s], s.date in ^date_list) |> where([s], s.date in ^date_list)
end end
def list_shifts_by_user_from_list_of_dates(user_id, date_list) do def list_shifts_by_user_from_list_of_dates(user_id, date_list) do
query_shifts_by_user_from_list_of_dates(user_id, date_list) user_id
|> query_shifts_by_user_from_list_of_dates(date_list)
|> Repo.all() |> Repo.all()
end end

View file

@ -1,5 +1,4 @@
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
@ -59,7 +58,7 @@ defmodule Shift73k.Shifts.Templates.ShiftTemplate do
[] []
end end
end) end)
|> validate_inclusion(:time_zone, Timex.timezones(), |> validate_inclusion(:time_zone, Tzdata.zone_list(),
message: "must be a valid IANA tz database time zone" message: "must be a valid IANA tz database time zone"
) )
end end
@ -70,7 +69,8 @@ defmodule Shift73k.Shifts.Templates.ShiftTemplate do
def shift_length(%ShiftTemplate{time_end: time_end, time_start: time_start}) do def shift_length(%ShiftTemplate{time_end: time_end, time_start: time_start}) do
time_end time_end
|> Timex.diff(time_start, :minute) |> Time.diff(time_start)
|> Integer.floor_div(60)
|> shift_length() |> shift_length()
end end
@ -79,11 +79,4 @@ defmodule Shift73k.Shifts.Templates.ShiftTemplate do
def shift_length(time_end, time_start), def shift_length(time_end, time_start),
do: shift_length(%ShiftTemplate{time_end: time_end, time_start: 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}
end
end end

View file

@ -68,16 +68,27 @@ defmodule Shift73kWeb.LiveHelpers do
end) end)
end end
def format_shift_time(time), do: Timex.format!(time, "{h12}:{m}{am}") def format_shift_time(time) do
time
|> Calendar.strftime("%-I:%M%P")
|> String.trim_trailing("m")
end
def format_shift_length(shift_template) do def format_shift_length(%ShiftTemplate{} = shift_template) do
shift_template shift_template
|> ShiftTemplate.shift_length() |> ShiftTemplate.shift_length()
|> Timex.Duration.from_minutes() |> format_shift_length()
|> Timex.format_duration() end
|> String.replace("PT", "")
|> String.replace("H", "h ") def format_shift_length(minutes) when is_integer(minutes) do
|> String.replace("M", "m") h = Integer.floor_div(minutes, 60)
|> String.trim() m = rem(minutes, 60)
cond do
h > 0 && m > 0 -> "#{h}h #{m}m"
h > 0 -> "#{h}h"
m > 0 -> "#{m}m"
true -> "0m"
end
end end
end end

View file

@ -7,7 +7,7 @@
<% months = Map.keys(data) %> <% months = Map.keys(data) %>
<dd> <dd>
<%= for {m, i} <- Enum.with_index(months, 1) do %> <%= for {m, i} <- Enum.with_index(months, 1) do %>
<%= data |> Map.get(m) |> hd() |> Timex.format!("{Mshort}") %>: <%= data |> Map.get(m) |> hd() |> Calendar.strftime("%b") %>:
<% days = Map.get(data, m) %> <% days = Map.get(data, m) %>
<%= for {d, i} <- Enum.with_index(days, 1) do %> <%= for {d, i} <- Enum.with_index(days, 1) do %>
<%= d.day %><%= if i < length(days) do %>,<% end %> <%= d.day %><%= if i < length(days) do %>,<% end %>

View file

@ -1,10 +1,8 @@
defmodule Shift73kWeb.ShiftAssignLive.Index do defmodule Shift73kWeb.ShiftAssignLive.Index do
use Shift73kWeb, :live_view use Shift73kWeb, :live_view
use Timex
alias Ecto.Multi alias Ecto.Multi
alias Shift73k.Repo alias Shift73k.Repo
alias Shift73k.EctoEnums.WeekdayEnum
alias Shift73k.Shifts alias Shift73k.Shifts
alias Shift73k.Shifts.Shift alias Shift73k.Shifts.Shift
alias Shift73k.Shifts.Templates alias Shift73k.Shifts.Templates
@ -27,8 +25,6 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
@impl true @impl true
def handle_params(_params, _url, socket) do def handle_params(_params, _url, socket) do
user = socket.assigns.current_user
socket socket
|> init_shift_templates() |> init_shift_templates()
|> init_shift_template() |> init_shift_template()
@ -36,8 +32,8 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
|> assign_shift_length() |> assign_shift_length()
|> assign_shift_template_changeset() |> assign_shift_template_changeset()
|> assign_modal_close_handlers() |> assign_modal_close_handlers()
|> assign(:day_names, day_names(user.week_start_at)) |> init_today(Date.utc_today())
|> init_today(Timex.today()) |> init_day_names()
|> update_calendar() |> update_calendar()
|> live_noreply() |> live_noreply()
end end
@ -61,7 +57,11 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
end end
defp init_today(socket, today) do defp init_today(socket, today) do
assign(socket, current_date: today, cursor_date: today) 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)
end end
defp assign_shift_template_changeset(%{assigns: %{shift_template: shift}} = socket) do defp assign_shift_template_changeset(%{assigns: %{shift_template: shift}} = socket) do
@ -105,27 +105,26 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
{label, template.id} {label, template.id}
end end
defp rotate_week(week_start_at) do defp init_day_names(%{assigns: %{current_user: user, current_date: today}} = socket) do
{a, b} = Enum.split_while(WeekdayEnum.__enum_map__(), fn {k, _v} -> k != week_start_at end) week_start = Date.beginning_of_week(today, user.week_start_at)
b ++ a
end
defp day_names(week_start_at) do day_names =
week_start_at week_start
|> rotate_week() |> Date.range(Date.add(week_start, 6))
|> Keyword.values() |> Enum.map(&Calendar.strftime(&1, "%a"))
|> Enum.map(&Timex.day_shortname/1)
assign(socket, :day_names, day_names)
end end
defp date_range(cursor_date, week_start_at) do defp date_range(cursor_date, week_start_at) do
last = last =
cursor_date cursor_date
|> Timex.end_of_month() |> Date.end_of_month()
|> Timex.end_of_week(week_start_at) |> Date.end_of_week(week_start_at)
cursor_date cursor_date
|> Timex.beginning_of_month() |> Date.beginning_of_month()
|> Timex.beginning_of_week(week_start_at) |> Date.beginning_of_week(week_start_at)
|> Date.range(last) |> Date.range(last)
end end
@ -134,26 +133,20 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
assign(socket, :date_range, date_range) assign(socket, :date_range, date_range)
end end
defp week_rows(%Date.Range{} = date_range) do
Interval.new(from: date_range.first, until: date_range.last, right_open: false)
|> Stream.map(&NaiveDateTime.to_date(&1))
|> Enum.chunk_every(7)
end
defp assign_week_rows(%{assigns: %{date_range: date_range}} = socket) do defp assign_week_rows(%{assigns: %{date_range: date_range}} = socket) do
assign(socket, :week_rows, week_rows(date_range)) assign(socket, :week_rows, Enum.chunk_every(date_range, 7))
end end
def day_color(day, current_date, cursor_date, selected_days) do def day_color(day, current_date, cursor_date, selected_days) do
cond do cond do
Enum.member?(selected_days, Date.to_string(day)) -> Enum.member?(selected_days, Date.to_string(day)) ->
cond do cond do
Timex.compare(day, current_date, :days) == 0 -> "bg-triangle-info text-white" Date.compare(day, current_date) == :eq -> "bg-triangle-info text-white"
day.month != cursor_date.month -> "bg-triangle-light text-gray" day.month != cursor_date.month -> "bg-triangle-light text-gray"
true -> "bg-triangle-white" true -> "bg-triangle-white"
end end
Timex.compare(day, current_date, :days) == 0 -> Date.compare(day, current_date) == :eq ->
"bg-info text-white" "bg-info text-white"
day.month != cursor_date.month -> day.month != cursor_date.month ->
@ -221,15 +214,16 @@ defmodule Shift73kWeb.ShiftAssignLive.Index do
end end
@impl true @impl true
def handle_event("month-nav", %{"month" => direction}, socket) do def handle_event("month-nav", %{"month" => nav}, socket) do
new_cursor = new_cursor =
cond do cond do
direction == "now" -> nav == "now" ->
Timex.today() Date.utc_today()
true -> true ->
months = (direction == "prev" && -1) || 1 socket.assigns.cursor_date
Timex.shift(socket.assigns.cursor_date, months: months) |> Date.add((nav == "prev" && -30) || 30)
|> cursor_date()
end end
socket socket

View file

@ -118,7 +118,7 @@
list: "tz_list" list: "tz_list"
%> %>
<datalist id="tz_list"> <datalist id="tz_list">
<%= for tz_name <- Timex.timezones() do %> <%= for tz_name <- Tzdata.zone_list() do %>
<option value="<%= tz_name %>"></option> <option value="<%= tz_name %>"></option>
<% end %> <% end %>
end end
@ -171,10 +171,10 @@
<%# month navigation %> <%# month navigation %>
<div class="d-flex justify-content-between align-items-end mt-4"> <div class="d-flex justify-content-between align-items-end mt-4">
<h3 class="text-muted mb-0"> <h3 class="text-muted mb-0">
<%= Timex.format!(@cursor_date, "{Mfull} {YYYY}") %> <%= Calendar.strftime(@cursor_date, "%B %Y") %>
</h3> </h3>
<div> <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(Timex.today(), :month), do: "disabled" %>> <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"] %> <%= icon_div @socket, "bi-asterisk", [class: "icon baseline"] %>
<span class="d-none d-sm-inline">Today</span> <span class="d-none d-sm-inline">Today</span>
</button> </button>
@ -206,7 +206,7 @@
<%= for day <- week do %> <%= for day <- week do %>
<td class="<%= day_color(day, @current_date, @cursor_date, @selected_days) %>" phx-click="select-day" phx-value-day="<%= day %>"> <td class="<%= day_color(day, @current_date, @cursor_date, @selected_days) %>" phx-click="select-day" phx-value-day="<%= day %>">
<%= Timex.format!(day, "{0D}") %><%= if day.month != @cursor_date.month, do: "-#{Timex.format!(day, "{Mshort}")}" %> <%= Calendar.strftime(day, "%d") %><%= if day.month != @cursor_date.month, do: "-#{Calendar.strftime(day, "%b")}" %>
<% day_shifts = Enum.filter(@known_shifts, fn s -> s.date == day end) %> <% day_shifts = Enum.filter(@known_shifts, fn s -> s.date == day end) %>
<% shifts_to_show = shifts_to_show(day_shifts) %> <% shifts_to_show = shifts_to_show(day_shifts) %>
@ -214,7 +214,7 @@
<%= for shift <- shifts_to_show do %> <%= for shift <- shifts_to_show do %>
<span class="badge bg-primary text-start d-block"> <span class="badge bg-primary text-start d-block">
<span> <span>
<%= shift.time_start |> Timex.format!("{h12}:{m}{am}") |> String.trim_trailing("m") %> <%= format_shift_time(shift.time_start) %>
<%= shift.subject %> <%= shift.subject %>
</span> </span>
</span> </span>

View file

@ -1,6 +1,5 @@
defmodule Shift73kWeb.ShiftLive.Index do defmodule Shift73kWeb.ShiftLive.Index do
use Shift73kWeb, :live_view use Shift73kWeb, :live_view
use Timex
alias Shift73k.Shifts alias Shift73k.Shifts
alias Shift73k.Shifts.Shift alias Shift73k.Shifts.Shift
@ -21,9 +20,8 @@ defmodule Shift73kWeb.ShiftLive.Index do
if Roles.can?(current_user, shift, live_action) do if Roles.can?(current_user, shift, live_action) do
socket socket
|> init_today(Timex.today()) |> init_today(Date.utc_today())
|> assign_date_range() |> update_agenda()
|> assign_known_shifts()
|> assign(:delete_shift, nil) |> assign(:delete_shift, nil)
|> apply_action(socket.assigns.live_action, params) |> apply_action(socket.assigns.live_action, params)
|> live_noreply() |> live_noreply()
@ -49,7 +47,11 @@ defmodule Shift73kWeb.ShiftLive.Index do
defp shift_from_params(_params), do: %Shift{} defp shift_from_params(_params), do: %Shift{}
defp init_today(socket, today) do defp init_today(socket, today) do
assign(socket, current_date: today, cursor_date: today) 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)
end end
defp assign_date_range(%{assigns: %{cursor_date: cursor_date}} = socket) do defp assign_date_range(%{assigns: %{cursor_date: cursor_date}} = socket) do
@ -58,8 +60,8 @@ defmodule Shift73kWeb.ShiftLive.Index do
defp date_range(cursor_date) do defp date_range(cursor_date) do
cursor_date cursor_date
|> Timex.beginning_of_month() |> Date.beginning_of_month()
|> Date.range(Timex.end_of_month(cursor_date)) |> Date.range(Date.end_of_month(cursor_date))
end end
defp assign_known_shifts(socket) do defp assign_known_shifts(socket) do
@ -68,6 +70,12 @@ defmodule Shift73kWeb.ShiftLive.Index do
assign(socket, :shifts, shifts) assign(socket, :shifts, shifts)
end end
defp update_agenda(socket) do
socket
|> assign_date_range()
|> assign_known_shifts()
end
@impl true @impl true
def handle_event("delete", %{"id" => id}, socket) do def handle_event("delete", %{"id" => id}, socket) do
shift = Shifts.get_shift!(id) shift = Shifts.get_shift!(id)
@ -77,21 +85,21 @@ defmodule Shift73kWeb.ShiftLive.Index do
end end
@impl true @impl true
def handle_event("month-nav", %{"month" => direction}, socket) do def handle_event("month-nav", %{"month" => nav}, socket) do
new_cursor = new_cursor =
cond do cond do
direction == "now" -> nav == "now" ->
Timex.today() Date.utc_today()
true -> true ->
months = (direction == "prev" && -1) || 1 socket.assigns.cursor_date
Timex.shift(socket.assigns.cursor_date, months: months) |> Date.add((nav == "prev" && -30) || 30)
|> cursor_date()
end end
socket socket
|> assign(:cursor_date, new_cursor) |> assign(:cursor_date, new_cursor)
|> assign_date_range() |> update_agenda()
|> assign_known_shifts()
|> live_noreply() |> live_noreply()
end end
end end

View file

@ -1,76 +1,84 @@
<div class="row justify-content-start justify-content-sm-center"> <div class="row justify-content-start justify-content-sm-center">
<div class="col-md-10 col-xl-10"> <div class="col-md-10 col-xl-10">
<h2 class="mb-3 mb-sm-0"> <h2 class="mb-3 mb-sm-0">
<%= icon_div @socket, "bi-card-list", [class: "icon baseline"] %> <%= icon_div @socket, "bi-card-list", [class: "icon baseline"] %>
My Shifts My Shifts
</h2> </h2>
<%# month navigation %> <div class="row justify-content-start justify-content-sm-center">
<div class="d-flex justify-content-between align-items-end mt-4"> <div class="col-md-10 col-xl-10">
<h3 class="text-muted mb-0">
<%= Timex.format!(@cursor_date, "{Mfull} {YYYY}") %>
</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(Timex.today(), :month), do: "disabled" %>>
<%= icon_div @socket, "bi-asterisk", [class: "icon baseline"] %>
<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"] %>
<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;"] %>
</button>
</div>
</div>
<dl> <%# month navigation %>
<%= for day <- Enum.to_list(@date_range) do %> <div class="d-flex justify-content-between align-items-end my-4">
<%= if Date.day_of_week(day, @current_user.week_start_at) == 1 do %> <h3 class="text-muted mb-0">
<div class="border-top mt-4 mb-4"></div> <%= Calendar.strftime(@cursor_date, "%B %Y") %>
<% end %> </h3>
<dt> <div>
<%= Timex.format!(day, "{WDfull}, {Mshort} {D}") %> <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" %>>
</dt> <%= icon_div @socket, "bi-asterisk", [class: "icon baseline"] %>
<% day_shifts = Enum.filter(@shifts, fn s -> s.date == day end) %> <span class="d-none d-sm-inline">Today</span>
<%= if !Enum.empty?(day_shifts) do %> </button>
<dd id="day-<%= day.day %>"> <button type="button" phx-click="month-nav" phx-value-month="prev" class="btn btn-primary">
<%= for shift <- day_shifts do %> <%= icon_div @socket, "bi-chevron-left", [class: "icon baseline"] %>
<div class="row gx-2" id="shift-<%= shift.id %>"> <span class="d-none d-sm-inline">Prev</span>
<div class="col-4 col-md-3 col-lg-2 text-end"> </button>
<div> <button type="button" phx-click="month-nav" phx-value-month="next" class="btn btn-primary">
<%= format_shift_time(shift.time_start) |> String.trim_trailing("m") %> <span class="d-none d-sm-inline">Next</span>
&mdash; <%= icon_div @socket, "bi-chevron-right", [class: "icon baseline", style: "margin-left:0.125rem;"] %>
<%= format_shift_time(shift.time_end) |> String.trim_trailing("m") %> </button>
</div>
<div style="font-size: smaller;"><%= shift.time_zone %></div>
</div>
<div class="col-8 col-md-9 col-lg-10">
<div>
<%= shift.subject %>
<%= if shift.location do %>
<span class="text-muted">(<%= shift.location %>)</span>
<% end %>
</div>
<div style="font-size: smaller;"><%= shift.description %></div>
<div style="font-size: smaller;">
<span><%= link "Delete", to: "#", phx_click: "delete", phx_value_id: shift.id, data: [confirm: "Are you sure?"] %></span>
</div>
</div> </div>
</div> </div>
<% end %>
</dd>
<% else %> <dl>
<dd><em>Nothing scheduled</em></dd> <%= for day <- Enum.to_list(@date_range) do %>
<% end %> <%= if Date.day_of_week(day, @current_user.week_start_at) == 1 do %>
<% end %> <div class="border-top mt-4 mb-4"></div>
</dl> <% end %>
<dt>
<%= Calendar.strftime(day, "%A, %b %-d") %>
</dt>
<% day_shifts = Enum.filter(@shifts, fn s -> s.date == day end) %>
<%= if !Enum.empty?(day_shifts) do %>
<dd id="day-<%= day.day %>">
<%= for shift <- day_shifts do %>
<div class="row gx-2" id="shift-<%= shift.id %>">
<div class="col-4 col-md-3 col-xl-2 text-end">
<div>
<%= format_shift_time(shift.time_start) %>
&mdash;
<%= format_shift_time(shift.time_end) %>
</div>
<div style="font-size: smaller;"><%= shift.time_zone %></div>
</div>
<div class="col-8 col-md-9 col-xl-10">
<div>
<%= shift.subject %>
<%= if shift.location do %>
<span class="text-muted">(<%= shift.location %>)</span>
<% end %>
</div>
<div style="font-size: smaller;"><%= shift.description %></div>
<div style="font-size: smaller;">
<span><%= link "Delete", to: "#", phx_click: "delete", phx_value_id: shift.id, data: [confirm: "Are you sure?"] %></span>
</div>
</div>
</div>
<% end %>
</dd>
<% else %>
<dd><em>Nothing scheduled</em></dd>
<% end %>
<% end %>
</dl>
</div>
</div>
</div> </div>

View file

@ -1,6 +1,5 @@
defmodule Shift73kWeb.ShiftTemplateLive.DeleteComponent do defmodule Shift73kWeb.ShiftTemplateLive.DeleteComponent do
use Shift73kWeb, :live_component use Shift73kWeb, :live_component
use Timex
alias Shift73k.Shifts.Templates alias Shift73k.Shifts.Templates

View file

@ -90,7 +90,7 @@
list: "tz_list" list: "tz_list"
%> %>
<datalist id="tz_list"> <datalist id="tz_list">
<%= for tz_name <- Timex.timezones() do %> <%= for tz_name <- Tzdata.zone_list() do %>
<option value="<%= tz_name %>"></option> <option value="<%= tz_name %>"></option>
<% end %> <% end %>
end end

View file

@ -1,6 +1,5 @@
defmodule Shift73kWeb.ShiftTemplateLive.Index do defmodule Shift73kWeb.ShiftTemplateLive.Index do
use Shift73kWeb, :live_view use Shift73kWeb, :live_view
use Timex
alias Shift73k.Accounts alias Shift73k.Accounts
alias Shift73k.Shifts.Templates alias Shift73k.Shifts.Templates

View file

@ -14,7 +14,13 @@ defmodule Shift73kWeb.UserLive.Settings.WeekStart do
end end
def week_start_options do def week_start_options do
WeekdayEnum.__enum_map__() |> Enum.map(fn {d, n} -> {Timex.day_name(n), d} end) {week_start_at, _} = WeekdayEnum.__enum_map__() |> hd()
week_start = Date.beginning_of_week(Date.utc_today(), week_start_at)
week_start
|> Date.range(Date.add(week_start, 6))
|> Enum.map(&Calendar.strftime(&1, "%A"))
|> Enum.zip(Keyword.keys(WeekdayEnum.__enum_map__()))
end end
@impl true @impl true

View file

@ -1,6 +1,5 @@
defmodule Shift73kWeb.UserManagementLive.Index do defmodule Shift73kWeb.UserManagementLive.Index do
use Shift73kWeb, :live_view use Shift73kWeb, :live_view
use Timex
import Ecto.Query import Ecto.Query
import Shift73k.Util.Dt import Shift73k.Util.Dt
@ -200,7 +199,7 @@ defmodule Shift73kWeb.UserManagementLive.Index do
def dt_out(ndt) do def dt_out(ndt) do
ndt ndt
|> Timex.to_datetime(app_time_zone()) |> DateTime.from_naive!(app_time_zone())
|> Timex.format!("{YYYY} {Mshort} {D}, {h12}:{m} {AM}") |> Calendar.strftime("%Y %b %-d, %-I:%M %p")
end end
end end

View file

@ -92,7 +92,7 @@
</dt> </dt>
<dd class="d-inline d-sm-block col-auto"> <dd class="d-inline d-sm-block col-auto">
<span class="visually-hidden"><%= user.confirmed_at && "Yes" || "No" %></span> <span class="visually-hidden"><%= user.confirmed_at && "Yes" || "No" %></span>
<input type="checkbox" class="form-check-input" aria-hidden="true" <%= user.confirmed_at && "checked" || "" %>> <input type="checkbox" class="form-check-input" aria-hidden="true" <%= user.confirmed_at && "checked" || "" %> disabled>
</dd> </dd>
</dl> </dl>
@ -174,7 +174,7 @@
<td class="align-middle" style="white-space: nowrap;"><%= dt_out(user.inserted_at) %></td> <td class="align-middle" style="white-space: nowrap;"><%= dt_out(user.inserted_at) %></td>
<td class="align-middle"> <td class="align-middle">
<span class="visually-hidden"><%= user.confirmed_at && "Confirmed" || "Not confirmed" %></span> <span class="visually-hidden"><%= user.confirmed_at && "Confirmed" || "Not confirmed" %></span>
<input type="checkbox" class="form-check-input" aria-hidden="true" <%= user.confirmed_at && "checked" || "" %>> <input type="checkbox" class="form-check-input" aria-hidden="true" <%= user.confirmed_at && "checked" || "" %> disabled>
</td> </td>
<td class="align-middle text-end text-nowrap"> <td class="align-middle text-end text-nowrap">

View file

@ -52,7 +52,8 @@ 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"},
{:timex, "~> 3.6"} {:tzdata, "~> 1.1"},
{:nimble_csv, "~> 1.0"}
] ]
end end

View file

@ -27,6 +27,7 @@
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "1.5.0", "203ef35ef3389aae6d361918bf3f952fa17a09e8e43b5aa592b93eba05d0fb8d", [:mix], [], "hexpm", "55a94c0f552249fc1a3dd9cd2d3ab9de9d3c89b559c2bd01121f824834f24746"}, "mime": {:hex, :mime, "1.5.0", "203ef35ef3389aae6d361918bf3f952fa17a09e8e43b5aa592b93eba05d0fb8d", [:mix], [], "hexpm", "55a94c0f552249fc1a3dd9cd2d3ab9de9d3c89b559c2bd01121f824834f24746"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"nimble_csv": {:hex, :nimble_csv, "1.1.0", "b1dba4a86be9e03065c9de829050468e591f569100332db949e7ce71be0afc25", [:mix], [], "hexpm", "e986755bc302832cac429be6deda0fc9d82d3c82b47abefb68b3c17c9d949a3f"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"phoenix": {:hex, :phoenix, "1.5.8", "71cfa7a9bb9a37af4df98939790642f210e35f696b935ca6d9d9c55a884621a4", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "35ded0a32f4836168c7ab6c33b88822eccd201bcd9492125a9bea4c54332d955"}, "phoenix": {:hex, :phoenix, "1.5.8", "71cfa7a9bb9a37af4df98939790642f210e35f696b935ca6d9d9c55a884621a4", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "35ded0a32f4836168c7ab6c33b88822eccd201bcd9492125a9bea4c54332d955"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.2.1", "13f124cf0a3ce0f1948cf24654c7b9f2347169ff75c1123f44674afee6af3b03", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 2.15", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "478a1bae899cac0a6e02be1deec7e2944b7754c04e7d4107fc5a517f877743c0"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.2.1", "13f124cf0a3ce0f1948cf24654c7b9f2347169ff75c1123f44674afee6af3b03", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 2.15", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "478a1bae899cac0a6e02be1deec7e2944b7754c04e7d4107fc5a517f877743c0"},

View file

@ -110,7 +110,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: Timex.timezones() |> Enum.random(), time_zone: Tzdata.zone_list() |> 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,