diff --git a/README.md b/README.md index 335eae2a..4b5c6f80 100644 --- a/README.md +++ b/README.md @@ -6,19 +6,19 @@ Written in Elixir & Phoenix LiveView, with Bootstrap v5. ## TODO -- [ ] Ability to edit shifts? -- [ ] Proper modal to delete shifts? -- [ ] Allow all-day items for notes, or require hours even for sick days? -- [ ] Implement proper shift/template/assign tests (views etc) +- [X] ~~*Proper modal to delete shifts?*~~ [2022-08-14] +- [ ] Update tests, which are probably all way out of date. But I also don't care that much for this project... ## Deploying +The below notes are old; I'm using a docker build to deploy this now. Will document when I have time. + ### New versions When improvements are made, we can update the deployed version like so: ```shell -cd /opt/shift73k +cd ${SHIFT73K_BASE_DIR} # update from master /usr/bin/git pull 73k master # fetch prod deps & compile @@ -27,10 +27,10 @@ MIX_ENV=prod /usr/bin/mix compile # perform any migrations MIX_ENV=prod /usr/bin/mix ecto.migrate # update node packages via package-lock.json -/usr/bin/npm --prefix /opt/shift73k/assets/ ci +/usr/bin/npm --prefix ./assets/ ci # rebuild static assets: -rm -rf /opt/shift73k/priv/static/* -/usr/bin/npm --prefix /opt/shift73k/assets/ run deploy +rm -rf ./priv/static/* +/usr/bin/npm --prefix ./assets/ run build MIX_ENV=prod /usr/bin/mix phx.digest # rebuild release MIX_ENV=prod /usr/bin/mix release --overwrite diff --git a/assets/package-lock.json b/assets/package-lock.json index 66947817..0bd90fcf 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -57,9 +57,9 @@ } }, "node_modules/@types/node": { - "version": "18.7.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.2.tgz", - "integrity": "sha512-ce7MIiaYWCFv6A83oEultwhBXb22fxwNOQf5DIxWA4WXvDQ7K+L0fbWl/YOfCzlR5B/uFkSnVBhPcOfOECcWvA==", + "version": "18.7.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.3.tgz", + "integrity": "sha512-LJgzOEwWuMTBxHzgBR/fhhBOWrvBjvO+zPteUgbbuQi80rYIZHrk1mNbRUqPZqSLP2H7Rwt1EFLL/tNLD1Xx/w==", "dev": true }, "node_modules/@types/phoenix": { @@ -1070,9 +1070,9 @@ "peer": true }, "@types/node": { - "version": "18.7.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.2.tgz", - "integrity": "sha512-ce7MIiaYWCFv6A83oEultwhBXb22fxwNOQf5DIxWA4WXvDQ7K+L0fbWl/YOfCzlR5B/uFkSnVBhPcOfOECcWvA==", + "version": "18.7.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.3.tgz", + "integrity": "sha512-LJgzOEwWuMTBxHzgBR/fhhBOWrvBjvO+zPteUgbbuQi80rYIZHrk1mNbRUqPZqSLP2H7Rwt1EFLL/tNLD1Xx/w==", "dev": true }, "@types/phoenix": { diff --git a/config/runtime.exs b/config/runtime.exs deleted file mode 100644 index 029407bf..00000000 --- a/config/runtime.exs +++ /dev/null @@ -1,83 +0,0 @@ -import Config - -# config/runtime.exs is executed for all environments, including -# during releases. It is executed after compilation and before the -# system starts, so it is typically used to load production configuration -# and secrets from environment variables or elsewhere. Do not define -# any compile-time configuration in here, as it won't be applied. -# The block below contains prod specific runtime configuration. - -# ## Using releases -# -# If you use `mix release`, you need to explicitly enable the server -# by passing the PHX_SERVER=true when you start it: -# -# PHX_SERVER=true bin/shift73k start -# -# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` -# script that automatically sets the env var above. -if System.get_env("PHX_SERVER") do - config :shift73k, Shift73kWeb.Endpoint, server: true -end - -if config_env() == :prod do - database_url = - System.get_env("DATABASE_URL") || - raise """ - environment variable DATABASE_URL is missing. - For example: ecto://USER:PASS@HOST/DATABASE - """ - - maybe_ipv6 = if System.get_env("ECTO_IPV6"), do: [:inet6], else: [] - - config :shift73k, Shift73k.Repo, - # ssl: true, - url: database_url, - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), - socket_options: maybe_ipv6 - - # The secret key base is used to sign/encrypt cookies and other secrets. - # A default value is used in config/dev.exs and config/test.exs but you - # want to use a different value for prod and you most likely don't want - # to check this value into version control, so we use an environment - # variable instead. - secret_key_base = - System.get_env("SECRET_KEY_BASE") || - raise """ - environment variable SECRET_KEY_BASE is missing. - You can generate one by calling: mix phx.gen.secret - """ - - host = System.get_env("PHX_HOST") || "example.com" - port = String.to_integer(System.get_env("PORT") || "4000") - - config :shift73k, Shift73kWeb.Endpoint, - url: [host: host, port: 443, scheme: "https"], - http: [ - # Enable IPv6 and bind on all interfaces. - # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. - # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html - # for details about using IPv6 vs IPv4 and loopback vs public addresses. - ip: {0, 0, 0, 0, 0, 0, 0, 0}, - port: port - ], - secret_key_base: secret_key_base - - # ## Configuring the mailer - # - # In production you need to configure the mailer to use a different adapter. - # Also, you may need to configure the Swoosh API client of your choice if you - # are not using SMTP. Here is an example of the configuration: - # - # config :shift73k, Shift73k.Mailer, - # adapter: Swoosh.Adapters.Mailgun, - # api_key: System.get_env("MAILGUN_API_KEY"), - # domain: System.get_env("MAILGUN_DOMAIN") - # - # For this example you need include a HTTP client required by Swoosh API client. - # Swoosh supports Hackney and Finch out of the box: - # - # config :swoosh, :api_client, Swoosh.ApiClient.Hackney - # - # See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details. -end diff --git a/lib/shift73k_web.ex b/lib/shift73k_web.ex index 5a03df6a..0eaba35a 100644 --- a/lib/shift73k_web.ex +++ b/lib/shift73k_web.ex @@ -105,9 +105,6 @@ defmodule Shift73kWeb do # Import basic rendering functionality (render, render_layout, etc) import Phoenix.View - # Import SVG Icon helper - import Shift73kWeb.IconHelpers - import Shift73kWeb.ErrorHelpers import Shift73kWeb.Gettext alias Shift73kWeb.Router.Helpers, as: Routes diff --git a/lib/shift73k_web/live/live_helpers.ex b/lib/shift73k_web/live/live_helpers.ex index ff98ac8d..36c33170 100644 --- a/lib/shift73k_web/live/live_helpers.ex +++ b/lib/shift73k_web/live/live_helpers.ex @@ -1,6 +1,5 @@ defmodule Shift73kWeb.LiveHelpers do import Phoenix.LiveView - import Phoenix.LiveView.Helpers alias Shift73k.Accounts alias Shift73k.Accounts.User @@ -19,27 +18,6 @@ defmodule Shift73kWeb.LiveHelpers do """ def live_okreply(socket), do: {:ok, socket} - @doc """ - Renders a component inside the `Shift73kWeb.ModalComponent` component. - - The rendered modal receives a `:return_to` option to properly update - the URL when the modal is closed. - - ## Examples - - <%= live_modal @socket, Shift73kWeb.PropertyLive.FormComponent, - id: @property.id || :new, - action: @live_action, - property: @property, - return_to: Routes.property_index_path(@socket, :index) %> - """ - def live_modal(socket, component, opts) do - modal_opts = [id: :modal, component: component, opts: opts] - # dirty little workaround for elixir complaining about socket being unused - _socket = socket - live_component(socket, Shift73kWeb.ModalComponent, modal_opts) - end - @doc """ Loads default assigns for liveviews """ diff --git a/lib/shift73k_web/live/shift_assign_live/index.html.heex b/lib/shift73k_web/live/shift_assign_live/index.html.heex index ce1d37a4..ce656afe 100644 --- a/lib/shift73k_web/live/shift_assign_live/index.html.heex +++ b/lib/shift73k_web/live/shift_assign_live/index.html.heex @@ -1,10 +1,15 @@ <%= if @delete_days_shifts do %> - <%= live_modal @socket, Shift73kWeb.ShiftAssignLive.DeleteComponent, + <.live_component + module={Shift73kWeb.ModalComponent} + id="modal" + component={Shift73kWeb.ShiftAssignLive.DeleteComponent} + opts={[ id: "delete-days-shifts-#{@current_user.id}", title: "Delete Shifts From Selected Days", delete_days_shifts: @delete_days_shifts, current_user: @current_user - %> + ]} + /> <% end %> diff --git a/lib/shift73k_web/live/shift_live/index.html.heex b/lib/shift73k_web/live/shift_live/index.html.heex index bc9cdf08..b599bd8e 100644 --- a/lib/shift73k_web/live/shift_live/index.html.heex +++ b/lib/shift73k_web/live/shift_live/index.html.heex @@ -1,8 +1,14 @@ <%= if @delete_shift do %> - <%= live_modal @socket, Shift73kWeb.ShiftLive.DeleteComponent, + <.live_component + module={Shift73kWeb.ModalComponent} + id="modal" + component={Shift73kWeb.ShiftLive.DeleteComponent} + opts={[ id: @delete_shift.id, title: "Delete Shift Template", - delete_shift: @delete_shift %> + delete_shift: @delete_shift + ]} + /> <% end %> diff --git a/lib/shift73k_web/live/shift_template_live/index.html.heex b/lib/shift73k_web/live/shift_template_live/index.html.heex index 45faa445..62abcdec 100644 --- a/lib/shift73k_web/live/shift_template_live/index.html.heex +++ b/lib/shift73k_web/live/shift_template_live/index.html.heex @@ -1,17 +1,29 @@ <%= if @live_action in [:new, :edit, :clone] do %> - <%= live_modal @socket, Shift73kWeb.ShiftTemplateLive.FormComponent, - id: @shift_template.id || :new, - title: @page_title, - action: @live_action, - shift_template: @shift_template, - current_user: @current_user %> + <.live_component + module={Shift73kWeb.ModalComponent} + id="modal" + component={Shift73kWeb.ShiftTemplateLive.FormComponent} + opts={[ + id: @shift_template.id || :new, + title: @page_title, + action: @live_action, + shift_template: @shift_template, + current_user: @current_user + ]} + /> <% end %> <%= if @delete_shift_template do %> - <%= live_modal @socket, Shift73kWeb.ShiftTemplateLive.DeleteComponent, + <.live_component + module={Shift73kWeb.ModalComponent} + id="modal" + component={Shift73kWeb.ShiftTemplateLive.DeleteComponent} + opts={[ id: @delete_shift_template.id, title: "Delete Shift Template", - delete_shift_template: @delete_shift_template %> + delete_shift_template: @delete_shift_template + ]} + /> <% end %> diff --git a/lib/shift73k_web/live/user/settings.html.heex b/lib/shift73k_web/live/user/settings.html.heex index e45e8cee..e769ec43 100644 --- a/lib/shift73k_web/live/user/settings.html.heex +++ b/lib/shift73k_web/live/user/settings.html.heex @@ -6,10 +6,10 @@ </h2> <div class="row justify-content-center justify-content-md-start"> - <%= live_component @socket, Shift73kWeb.UserLive.Settings.Email, id: "email-#{@current_user.id}", current_user: @current_user %> - <%= live_component @socket, Shift73kWeb.UserLive.Settings.Password, id: "password-#{@current_user.id}", current_user: @current_user %> - <%= live_component @socket, Shift73kWeb.UserLive.Settings.WeekStart, id: "week_start-#{@current_user.id}", current_user: @current_user %> - <%= live_component @socket, Shift73kWeb.UserLive.Settings.CalendarUrl, id: "calendar_url-#{@current_user.id}", current_user: @current_user %> + <.live_component module={Shift73kWeb.UserLive.Settings.Email} id={"email-#{@current_user.id}"} current_user={@current_user} /> + <.live_component module={Shift73kWeb.UserLive.Settings.Password} id={"password-#{@current_user.id}"} current_user={@current_user} /> + <.live_component module={Shift73kWeb.UserLive.Settings.WeekStart} id={"week_start-#{@current_user.id}"} current_user={@current_user} /> + <.live_component module={Shift73kWeb.UserLive.Settings.CalendarUrl} id={"calendar_url-#{@current_user.id}"} current_user={@current_user} /> </div> </div> diff --git a/lib/shift73k_web/live/user_management/delete_component.ex b/lib/shift73k_web/live/user_management/delete_component.ex index b1c48aae..ee73804f 100644 --- a/lib/shift73k_web/live/user_management/delete_component.ex +++ b/lib/shift73k_web/live/user_management/delete_component.ex @@ -9,9 +9,13 @@ defmodule Shift73kWeb.UserManagement.DeleteComponent do end @impl true - def handle_event("confirm", %{"id" => id, "email" => email}, socket) do - id - |> Accounts.get_user() + def handle_event("confirm", %{"id" => id, "email" => email} = params, socket) do + IO.inspect(params) + + user = Accounts.get_user(id) + IO.inspect(user) + + user |> Accounts.delete_user() |> case do {:ok, _} -> diff --git a/lib/shift73k_web/live/user_management/index.html.heex b/lib/shift73k_web/live/user_management/index.html.heex index 912bb88b..110cd7de 100644 --- a/lib/shift73k_web/live/user_management/index.html.heex +++ b/lib/shift73k_web/live/user_management/index.html.heex @@ -1,18 +1,29 @@ <%= if @live_action in [:new, :edit] do %> - <%= live_modal @socket, Shift73kWeb.UserManagement.FormComponent, + <.live_component + module={Shift73kWeb.ModalComponent} + id="modal" + component={Shift73kWeb.UserManagement.FormComponent} + opts={[ id: @user.id || :new, title: @page_title, action: @live_action, user: @user, - current_user: @current_user %> + current_user: @current_user + ]} + /> <% end %> <%= if @delete_user do %> - <%= live_modal @socket, Shift73kWeb.UserManagement.DeleteComponent, + <.live_component + module={Shift73kWeb.ModalComponent} + id="modal" + component={Shift73kWeb.UserManagement.DeleteComponent} + opts={[ id: @delete_user.id, title: "Delete User", delete_user: @delete_user - %> + ]} + /> <% end %> diff --git a/lib/shift73k_web/templates/layout/_navbar.html.heex b/lib/shift73k_web/templates/layout/_navbar.html.heex index 4c81942d..c8ac8310 100644 --- a/lib/shift73k_web/templates/layout/_navbar.html.heex +++ b/lib/shift73k_web/templates/layout/_navbar.html.heex @@ -52,7 +52,7 @@ AND: There are no users -- [REGISTER] OR no registration allowed -- [LOG IN] %> - <%= else %> + <% else %> <%= if !Repo.exists?(User) || allow_registration() do %> <%= link nav_link_opts(@conn, to: Routes.user_registration_path(@conn, :new), class: "btn btn-outline-light") do %> diff --git a/lib/shift73k_web/views/icon_helpers.ex b/lib/shift73k_web/views/icon_helpers.ex deleted file mode 100644 index 048373f8..00000000 --- a/lib/shift73k_web/views/icon_helpers.ex +++ /dev/null @@ -1,38 +0,0 @@ -defmodule Shift73kWeb.IconHelpers do - @moduledoc """ - Generate SVG sprite use tags for SVG icons - """ - - use Phoenix.HTML - alias Shift73kWeb.Router.Helpers, as: Routes - - def icon_div(conn, name, div_opts \\ [], svg_opts \\ []) do - content_tag(:div, tag_opts(name, div_opts)) do - icon_svg(conn, name, svg_opts) - end - end - - def icon_svg(conn, name, opts \\ []) do - opts = aria_hidden?(opts) - - content_tag(:svg, tag_opts(name, opts)) do - ~E""" - <%= if title = Keyword.get(opts, :aria_label), do: content_tag(:title, title) %> - <%= tag(:use, "xlink:href": Routes.static_path(conn, "/images/icons.svg##{name}")) %> - """ - end - end - - defp tag_opts(name, opts) do - Keyword.update(opts, :class, name, fn c -> "#{c} #{name}" end) - end - - defp aria_hidden?(opts) do - case Keyword.get(opts, :aria_hidden) do - "false" -> Keyword.drop(opts, [:aria_hidden]) - false -> Keyword.drop(opts, [:aria_hidden]) - "true" -> opts - _ -> Keyword.put(opts, :aria_hidden, "true") - end - end -end diff --git a/priv/repo/migrations/20220814161100_fix_shifts_user_id_reference.exs b/priv/repo/migrations/20220814161100_fix_shifts_user_id_reference.exs new file mode 100644 index 00000000..c4222e3a --- /dev/null +++ b/priv/repo/migrations/20220814161100_fix_shifts_user_id_reference.exs @@ -0,0 +1,19 @@ +defmodule Shift73k.Repo.Migrations.FixShiftsUserIdReference do + use Ecto.Migration + + def up do + execute("ALTER TABLE shifts DROP CONSTRAINT shifts_user_id_fkey") + + alter table(:shifts) do + modify :user_id, references(:users, on_delete: :delete_all, type: :binary_id) + end + end + + def down do + execute("ALTER TABLE shifts DROP CONSTRAINT shifts_user_id_fkey") + + alter table(:shifts) do + modify :user_id, references(:users, on_delete: :nothing, type: :binary_id) + end + end +end