updated template management, including time_input: required fix
This commit is contained in:
parent
6a5d2346ff
commit
ada166fb41
7 changed files with 165 additions and 161 deletions
|
@ -0,0 +1,23 @@
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
Are you sure you want to delete "<%= @delete_shift_template.subject %>
|
||||||
|
(<%= format_shift_time(@delete_shift_template.time_start) %>
|
||||||
|
—
|
||||||
|
<%= format_shift_time(@delete_shift_template.time_end) %>)"?
|
||||||
|
|
||||||
|
</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_template.id,
|
||||||
|
phx_value_subject: @delete_shift_template.subject %>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
|
@ -1,19 +0,0 @@
|
||||||
<div class="modal-body">
|
|
||||||
|
|
||||||
Are you sure you want to delete "<%= @delete_shift_template.subject %>
|
|
||||||
(<%= format_shift_time(@delete_shift_template.time_start) %>
|
|
||||||
—
|
|
||||||
<%= format_shift_time(@delete_shift_template.time_end) %>)"?
|
|
||||||
|
|
||||||
</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_template.id,
|
|
||||||
phx_value_subject: @delete_shift_template.subject %>
|
|
||||||
|
|
||||||
</div>
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<%= form_for @changeset, "#", [
|
||||||
|
id: "shift_template-form",
|
||||||
|
phx_target: @myself,
|
||||||
|
phx_change: "validate",
|
||||||
|
phx_submit: "save"
|
||||||
|
], fn f -> %>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<%= label f, :subject, "Subject/Title", class: "form-label" %>
|
||||||
|
<div class="inner-addon left-addon mb-3" phx-feedback-for={input_id(f, :subject)}>
|
||||||
|
<i class="bi bi-tag icon is-left text-muted fs-5"></i>
|
||||||
|
<%= text_input f, :subject,
|
||||||
|
value: input_value(f, :subject),
|
||||||
|
class: input_class(f, :subject, "form-control"),
|
||||||
|
autofocus: true,
|
||||||
|
phx_debounce: 250,
|
||||||
|
aria_describedby: error_ids(f, :subject)
|
||||||
|
%>
|
||||||
|
<%= error_tag f, :subject %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row gx-2 gx-sm-3">
|
||||||
|
|
||||||
|
<div class="col-6" phx-feedback-for={input_id(f, :time_start)}>
|
||||||
|
<%= label f, :time_start, "Start", class: "form-label" %>
|
||||||
|
<%= time_input f, :time_start,
|
||||||
|
precision: :minute,
|
||||||
|
value: input_value(f, :time_start),
|
||||||
|
class: input_class(f, :time_start, "form-control"),
|
||||||
|
aria_describedby: error_ids(f, :time_start),
|
||||||
|
required: true
|
||||||
|
%>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-6" phx-feedback-for={input_id(f, :time_end)}>
|
||||||
|
<%= label f, :time_end, "End", class: "form-label" %>
|
||||||
|
<%= time_input f, :time_end,
|
||||||
|
precision: :minute,
|
||||||
|
value: input_value(f, :time_end),
|
||||||
|
class: input_class(f, :time_end, "form-control"),
|
||||||
|
aria_describedby: error_ids(f, :time_end),
|
||||||
|
required: true
|
||||||
|
%>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="valid-feedback d-block text-primary">Shift length: <%= @shift_length %></div>
|
||||||
|
|
||||||
|
<div class="phx-orphaned-feedback" phx-feedback-for={input_id(f, :time_start)}>
|
||||||
|
<%= error_tag f, :time_start %>
|
||||||
|
</div>
|
||||||
|
<div class="phx-orphaned-feedback" phx-feedback-for={input_id(f, :time_end)}>
|
||||||
|
<%= error_tag f, :time_end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<%= label f, :location, class: "form-label mt-3" %>
|
||||||
|
<div class="inner-addon left-addon mb-3" phx-feedback-for={input_id(f, :location)}>
|
||||||
|
<i class="bi bi-geo icon is-left text-muted fs-5"></i>
|
||||||
|
<%= text_input f, :location,
|
||||||
|
value: input_value(f, :location),
|
||||||
|
class: input_class(f, :location, "form-control"),
|
||||||
|
phx_debounce: 250,
|
||||||
|
aria_describedby: error_ids(f, :location)
|
||||||
|
%>
|
||||||
|
<%= error_tag f, :location %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<%= label f, :description, class: "form-label" %>
|
||||||
|
<div class="mb-3" phx-feedback-for={input_id(f, :description)}>
|
||||||
|
|
||||||
|
<%= textarea f, :description,
|
||||||
|
value: input_value(f, :description),
|
||||||
|
class: input_class(f, :description, "form-control"),
|
||||||
|
phx_debounce: 250,
|
||||||
|
aria_describedby: error_ids(f, :description)
|
||||||
|
%>
|
||||||
|
<%= error_tag f, :description %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<%= label f, :time_zone, class: "form-label" %>
|
||||||
|
<div class="inner-addon left-addon mb-3" phx-feedback-for={input_id(f, :time_zone)}>
|
||||||
|
<i class="bi bi-map icon is-left text-muted fs-5"></i>
|
||||||
|
<%= text_input f, :time_zone,
|
||||||
|
value: input_value(f, :time_zone),
|
||||||
|
class: input_class(f, :time_zone, "form-control"),
|
||||||
|
phx_debounce: 250,
|
||||||
|
list: "tz_list"
|
||||||
|
%>
|
||||||
|
<datalist id="tz_list">
|
||||||
|
<%= for tz_name <- Tzdata.zone_list() do %>
|
||||||
|
<option value={tz_name}></option>
|
||||||
|
<% end %>
|
||||||
|
</datalist>
|
||||||
|
<div class="valid-feedback d-block text-primary">Type to search & select from list of known <%= link "IANA tz database", to: "https://en.wikipedia.org/wiki/List_of_tz_database_time_zones", target: "_blank" %> time zones</div>
|
||||||
|
<%= error_tag f, :time_zone %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
|
||||||
|
<%= link "Cancel", to: "#", class: "btn btn-outline-dark", phx_click: "hide", phx_target: "##{@modal_id}" %>
|
||||||
|
<%= submit "Save",
|
||||||
|
class: "btn btn-primary ",
|
||||||
|
disabled: !@changeset.valid?,
|
||||||
|
aria_disabled: !@changeset.valid? && "true" || false,
|
||||||
|
phx_disable_with: "Saving..."
|
||||||
|
%>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
</div>
|
|
@ -1,116 +0,0 @@
|
||||||
<%= f = form_for @changeset, "#",
|
|
||||||
id: "shift_template-form",
|
|
||||||
phx_target: @myself,
|
|
||||||
phx_change: "validate",
|
|
||||||
phx_submit: "save" %>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
|
|
||||||
<%= label f, :subject, "Subject/Title", class: "form-label" %>
|
|
||||||
<div class="inner-addon left-addon mb-3" phx-feedback-for="<%= input_id(f, :subject) %>">
|
|
||||||
<%= icon_div @socket, "bi-tag", [class: "icon is-left text-muted fs-5"] %>
|
|
||||||
<%= text_input f, :subject,
|
|
||||||
value: input_value(f, :subject),
|
|
||||||
class: input_class(f, :subject, "form-control"),
|
|
||||||
autofocus: true,
|
|
||||||
phx_debounce: 250,
|
|
||||||
aria_describedby: error_ids(f, :subject)
|
|
||||||
%>
|
|
||||||
<%= error_tag f, :subject %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row gx-2 gx-sm-3">
|
|
||||||
|
|
||||||
<div class="col-6" phx-feedback-for="<%= input_id(f, :time_start) %>">
|
|
||||||
<%= label f, :time_start, "Start", class: "form-label" %>
|
|
||||||
<%= time_input f, :time_start,
|
|
||||||
precision: :minute,
|
|
||||||
value: input_value(f, :time_start),
|
|
||||||
class: input_class(f, :time_start, "form-control"),
|
|
||||||
aria_describedby: error_ids(f, :time_start)
|
|
||||||
%>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-6" phx-feedback-for="<%= input_id(f, :time_end) %>">
|
|
||||||
<%= label f, :time_end, "End", class: "form-label" %>
|
|
||||||
<%= time_input f, :time_end,
|
|
||||||
precision: :minute,
|
|
||||||
value: input_value(f, :time_end),
|
|
||||||
class: input_class(f, :time_end, "form-control"),
|
|
||||||
aria_describedby: error_ids(f, :time_end)
|
|
||||||
%>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="valid-feedback d-block text-primary">Shift length: <%= @shift_length %></div>
|
|
||||||
|
|
||||||
<div class="phx-orphaned-feedback" phx-feedback-for="<%= input_id(f, :time_start) %>">
|
|
||||||
<%= error_tag f, :time_start %>
|
|
||||||
</div>
|
|
||||||
<div class="phx-orphaned-feedback" phx-feedback-for="<%= input_id(f, :time_end) %>">
|
|
||||||
<%= error_tag f, :time_end %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<%= label f, :location, class: "form-label mt-3" %>
|
|
||||||
<div class="inner-addon left-addon mb-3" phx-feedback-for="<%= input_id(f, :location) %>">
|
|
||||||
<%= icon_div @socket, "bi-geo", [class: "icon is-left text-muted fs-5"] %>
|
|
||||||
<%= text_input f, :location,
|
|
||||||
value: input_value(f, :location),
|
|
||||||
class: input_class(f, :location, "form-control"),
|
|
||||||
phx_debounce: 250,
|
|
||||||
aria_describedby: error_ids(f, :location)
|
|
||||||
%>
|
|
||||||
<%= error_tag f, :location %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<%= label f, :description, class: "form-label" %>
|
|
||||||
<div class="mb-3" phx-feedback-for="<%= input_id(f, :description) %>">
|
|
||||||
|
|
||||||
<%= textarea f, :description,
|
|
||||||
value: input_value(f, :description),
|
|
||||||
class: input_class(f, :description, "form-control"),
|
|
||||||
phx_debounce: 250,
|
|
||||||
aria_describedby: error_ids(f, :description)
|
|
||||||
%>
|
|
||||||
<%= error_tag f, :description %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<%= label f, :time_zone, class: "form-label" %>
|
|
||||||
<div class="inner-addon left-addon mb-3" phx-feedback-for="<%= input_id(f, :time_zone) %>">
|
|
||||||
<%= icon_div @socket, "bi-map", [class: "icon is-left text-muted fs-5"] %>
|
|
||||||
<%= text_input f, :time_zone,
|
|
||||||
value: input_value(f, :time_zone),
|
|
||||||
class: input_class(f, :time_zone, "form-control"),
|
|
||||||
phx_debounce: 250,
|
|
||||||
list: "tz_list"
|
|
||||||
%>
|
|
||||||
<datalist id="tz_list">
|
|
||||||
<%= for tz_name <- Tzdata.zone_list() do %>
|
|
||||||
<option value="<%= tz_name %>"></option>
|
|
||||||
<% end %>
|
|
||||||
</datalist>
|
|
||||||
<div class="valid-feedback d-block text-primary">Type to search & select from list of known <%= link "IANA tz database", to: "https://en.wikipedia.org/wiki/List_of_tz_database_time_zones", target: "_blank" %> time zones</div>
|
|
||||||
<%= error_tag f, :time_zone %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
|
|
||||||
<%= link "Cancel", to: "#", class: "btn btn-outline-dark", phx_click: "hide", phx_target: "##{@modal_id}" %>
|
|
||||||
<%= submit "Save",
|
|
||||||
class: "btn btn-primary ",
|
|
||||||
disabled: !@changeset.valid?,
|
|
||||||
aria_disabled: !@changeset.valid? && "true" || false,
|
|
||||||
phx_disable_with: "Saving..."
|
|
||||||
%>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
|
@ -20,12 +20,10 @@
|
||||||
|
|
||||||
<div class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
|
<div class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center">
|
||||||
<h2 class="mb-3 mb-sm-0">
|
<h2 class="mb-3 mb-sm-0">
|
||||||
<%= icon_div @socket, "bi-clock-history", [class: "icon baseline"] %>
|
<i class="bi bi-clock-history me-1"></i> My Shift Templates
|
||||||
My Shift Templates
|
|
||||||
</h2>
|
</h2>
|
||||||
<%= live_patch to: Routes.shift_template_index_path(@socket, :new), class: "btn btn-primary" do %>
|
<%= live_patch to: Routes.shift_template_index_path(@socket, :new), class: "btn btn-primary" do %>
|
||||||
<%= icon_div @socket, "bi-plus-circle-dotted", [class: "icon baseline"] %>
|
<i class="bi bi-plus-circle-dotted me-1"></i> New Shift Template
|
||||||
New Shift Template
|
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -39,13 +37,13 @@
|
||||||
<div class="card mt-4">
|
<div class="card mt-4">
|
||||||
<h5 class="card-header d-flex justify-content-between align-items-center">
|
<h5 class="card-header d-flex justify-content-between align-items-center">
|
||||||
<span class="visually-hidden">Subject:</span>
|
<span class="visually-hidden">Subject:</span>
|
||||||
<%= icon_div @socket, "bi-tag", [class: "icon baseline me-1"] %>
|
<i class="bi bi-tag me-1"></i>
|
||||||
<div class="w-100"><%= template.subject %></div>
|
<div class="w-100"><%= template.subject %></div>
|
||||||
<%= if template.id == @current_user.fave_shift_template_id do %>
|
<% fav_icon_data = 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"], [role: "img", aria_hidden: false, aria_label: "Unset as favorite", phx_click: "unset-user-fave-shift-template", class: "cursor-pointer"] %>
|
{"bi-star-fill", "Unset as favorite", "unset-user-fave-shift-template"}, else:
|
||||||
<% else %>
|
{"bi-star", "Set as favorite", "set-user-fave-shift-template"}
|
||||||
<%= icon_div @socket, "bi-star", [class: "icon baseline text-primary align-self-start ms-2"], [role: "img", aria_hidden: false, aria_label: "Set as favorite", phx_click: "set-user-fave-shift-template", phx_value_id: template.id, class: "cursor-pointer"] %>
|
%>
|
||||||
<% end %>
|
<i class={"bi #{elem(fav_icon_data, 0)} text-primary align-self-start ms-2 cursor-pointer"} role="img" aria-hidden="false" aria-label={elem(fav_icon_data, 1)} phx-click={elem(fav_icon_data, 2)} phx-value-id={template.id}></i>
|
||||||
</h5>
|
</h5>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
|
@ -53,7 +51,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row" class="text-end">
|
<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>
|
<span class="visually-hidden">Hours:</span>
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
|
@ -70,7 +68,7 @@
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row" class="text-end">
|
<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>
|
<span class="visually-hidden">Location:</span>
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
|
@ -83,7 +81,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row" class="text-end">
|
<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>
|
<span class="visually-hidden">Description:</span>
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
|
@ -99,24 +97,19 @@
|
||||||
|
|
||||||
<%= if Roles.can?(@current_user, template, :edit) do %>
|
<%= 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 %>
|
<%= 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"] %>
|
<i class="bi bi-pencil me-1"></i> Edit
|
||||||
Edit
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= if Roles.can?(@current_user, template, :clone) do %>
|
<%= if Roles.can?(@current_user, template, :clone) do %>
|
||||||
<%= live_patch to: Routes.shift_template_index_path(@socket, :clone, template), 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"] %>
|
<i class="bi bi-clipboard-plus me-1"></i> Clone
|
||||||
Clone
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%#= button "" %>
|
|
||||||
|
|
||||||
<%= if Roles.can?(@current_user, template, :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="<%= template.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"] %>
|
<i class="bi bi-trash me-1"></i> Delete
|
||||||
Delete
|
|
||||||
</button>
|
</button>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
|
|
||||||
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownUserMenu" data-bs-toggle="dropdown" aria-expanded="false">
|
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownNoUserMenu" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<i class="bi bi-person-circle me-1"></i> Hello?
|
<i class="bi bi-person-circle me-1"></i> Hello?
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownUserMenu">
|
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownNoUserMenu">
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<%= link nav_link_opts(@conn, to: Routes.user_registration_path(@conn, :new), class: "dropdown-item") do %>
|
<%= link nav_link_opts(@conn, to: Routes.user_registration_path(@conn, :new), class: "dropdown-item") do %>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
|
|
||||||
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownUserMenu" data-bs-toggle="dropdown" aria-expanded="false">
|
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownShiftsMenu" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<i class="bi bi-calendar2 me-1"></i> Shifts
|
<i class="bi bi-calendar2 me-1"></i> Shifts
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownUserMenu">
|
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownShiftsMenu">
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<%= link nav_link_opts(@conn, to: Routes.shift_assign_index_path(@conn, :index), class: "dropdown-item") do %>
|
<%= link nav_link_opts(@conn, to: Routes.shift_assign_index_path(@conn, :index), class: "dropdown-item") do %>
|
||||||
|
|
Loading…
Reference in a new issue