diff --git a/assets/js/alpine_helpers.js b/assets/js/alpine_helpers.js index 56a7d93..2d8bd93 100644 --- a/assets/js/alpine_helpers.js +++ b/assets/js/alpine_helpers.js @@ -35,3 +35,10 @@ window.markVersionAsSeen = (versionString) => { window.isVersionSeen = (versionString) => { return localStorage.getItem('seenVersion') === versionString } + +window.dispatchFor = (elementOrId, eventName, detail = {}) => { + const element = + typeof elementOrId === 'string' ? document.getElementById(elementOrId) : elementOrId + + element.dispatchEvent(new CustomEvent(eventName, { detail })) +} diff --git a/assets/js/app.js b/assets/js/app.js index 2be596d..f9accf3 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -39,7 +39,7 @@ let liveSocket = new LiveSocket(document.body.dataset.socketPath, Socket, { } }, hooks: { - supressEnterSubmission: { + 'supress-enter-submission': { mounted() { this.el.addEventListener('keypress', (event) => { if (event.key === 'Enter') { @@ -47,6 +47,29 @@ let liveSocket = new LiveSocket(document.body.dataset.socketPath, Socket, { } }) } + }, + 'formless-input': { + mounted() { + const subscribedEvents = this.el.dataset.subscribe.split(' ') + const eventName = this.el.dataset.eventName || '' + const identifier = this.el.dataset.identifier || '' + + subscribedEvents.forEach((domEvent) => { + this.el.addEventListener(domEvent, () => { + // This ensures that the event is pushed to the server after the input value has been updated + // so that the server has the most up-to-date value + setTimeout(() => { + this.pushEvent('formless-input', { + value: this.el.value, + id: identifier, + event: eventName, + dom_id: this.el.id, + dom_event: domEvent + }) + }, 0) + }) + }) + } } } }) diff --git a/lib/pinchflat/profiles/profiles_query.ex b/lib/pinchflat/profiles/profiles_query.ex new file mode 100644 index 0000000..caa1315 --- /dev/null +++ b/lib/pinchflat/profiles/profiles_query.ex @@ -0,0 +1,29 @@ +defmodule Pinchflat.Profiles.ProfilesQuery do + @moduledoc """ + Query helpers for the Profiles context. + + These methods are made to be one-ish liners used + to compose queries. Each method should strive to do + _one_ thing. These don't need to be tested as + they are just building blocks for other functionality + which, itself, will be tested. + """ + import Ecto.Query, warn: false + + alias Pinchflat.Profiles.MediaProfile + + # This allows the module to be aliased and query methods to be used + # all in one go + # usage: use Pinchflat.Profiles.ProfilesQuery + defmacro __using__(_opts) do + quote do + import Ecto.Query, warn: false + + alias unquote(__MODULE__) + end + end + + def new do + MediaProfile + end +end diff --git a/lib/pinchflat_web/components/core_components.ex b/lib/pinchflat_web/components/core_components.ex index 0bad772..0aeb34f 100644 --- a/lib/pinchflat_web/components/core_components.ex +++ b/lib/pinchflat_web/components/core_components.ex @@ -340,14 +340,15 @@ defmodule PinchflatWeb.CoreComponents do end) ~H""" -
- <.label for={@id}> +
+ <.label :if={@label} for={@id}> <%= @label %> <%= @label_suffix %> -
+
-
+ <%!-- This triggers a `change` event on the hidden input when the toggle is clicked --%> +
+
<.input type="text" name="unlock-pro-textbox" value="" />
diff --git a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/index.html.heex b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/index.html.heex index e3a2dee..caee38d 100644 --- a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/index.html.heex +++ b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/index.html.heex @@ -14,19 +14,7 @@
- <.table rows={@media_profiles} table_class="text-black dark:text-white"> - <:col :let={media_profile} label="Name"> - <.subtle_link href={~p"/media_profiles/#{media_profile.id}"}> - <%= media_profile.name %> - - - <:col :let={media_profile} label="Preferred Resolution"> - <%= media_profile.preferred_resolution %> - - <:col :let={media_profile} label="" class="flex justify-end"> - <.icon_link href={~p"/media_profiles/#{media_profile.id}/edit"} icon="hero-pencil-square" class="mr-4" /> - - + <%= live_render(@conn, PinchflatWeb.MediaProfiles.IndexTableLive) %>
diff --git a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/index_table_live.ex b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/index_table_live.ex new file mode 100644 index 0000000..9309a5a --- /dev/null +++ b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/index_table_live.ex @@ -0,0 +1,57 @@ +defmodule PinchflatWeb.MediaProfiles.IndexTableLive do + use PinchflatWeb, :live_view + use Pinchflat.Profiles.ProfilesQuery + + alias Pinchflat.Repo + + def render(assigns) do + ~H""" + <.table rows={@media_profiles} table_class="text-black dark:text-white"> + <:col :let={media_profile} label="Name"> + <.subtle_link href={~p"/media_profiles/#{media_profile.id}"}> + <%= media_profile.name %> + + + <:col :let={media_profile} label="Preferred Resolution"> + <%= media_profile.preferred_resolution %> + + <:col :let={media_profile} label="Enabled?"> + <.input + name={"media_profile[#{media_profile.id}][enabled]"} + id={"media_profile_#{media_profile.id}_enabled"} + phx-hook="formless-input" + data-subscribe="change" + data-event-name="toggle_enabled" + data-identifier={media_profile.id} + type="toggle" + /> + + <:col :let={media_profile} label="" class="flex justify-end"> + <.icon_link href={~p"/media_profiles/#{media_profile.id}/edit"} icon="hero-pencil-square" class="mr-4" /> + + + """ + end + + def mount(_params, _session, socket) do + new_assigns = %{ + media_profiles: get_media_profiles() + } + + {:ok, assign(socket, new_assigns)} + end + + def handle_event("formless-input", %{"event" => "toggle_enabled"} = params, socket) do + # should_enable = params["value"] == "true" + IO.inspect(params) + + {:noreply, socket} + end + + defp get_media_profiles do + ProfilesQuery.new() + |> where([mp], is_nil(mp.marked_for_deletion_at)) + |> order_by(asc: :name) + |> Repo.all() + end +end