diff --git a/lib/music_library_web/live/stats_live/top_albums.ex b/lib/music_library_web/live/stats_live/top_albums.ex index 42551b5b..2ef22bdd 100644 --- a/lib/music_library_web/live/stats_live/top_albums.ex +++ b/lib/music_library_web/live/stats_live/top_albums.ex @@ -1,111 +1,27 @@ defmodule MusicLibraryWeb.StatsLive.TopAlbums do - use MusicLibraryWeb, :live_component + use MusicLibraryWeb, :html alias MusicLibrary.Assets.Transform alias MusicLibrary.ListeningStats + alias MusicLibraryWeb.StatsLive.TopByPeriod + + attr :id, :string, required: true + attr :timezone, :string, required: true + attr :last_updated_uts, :any def live(assigns) do ~H""" - <.live_component module={__MODULE__} {assigns} id={@id} /> - """ - end - - @impl true - def render(assigns) do - ~H""" -
-

- {gettext("Top Albums")} -

- <.tabs class="mt-4"> - <.tabs_list active_tab={name_from_period(@period)} variant="segmented" size="xs"> - <:tab - class="flex-1" - name="top_albums_last_7_days" - phx-click={JS.push("set_period", value: %{period: "last_7_days"})} - phx-target={@myself} - > - {gettext("7d")} - - <:tab - class="flex-1" - name="top_albums_last_30_days" - phx-click={JS.push("set_period", value: %{period: "last_30_days"})} - phx-target={@myself} - > - {gettext("30d")} - - <:tab - class="flex-1" - name="top_albums_last_90_days" - phx-click={JS.push("set_period", value: %{period: "last_90_days"})} - phx-target={@myself} - > - {gettext("90d")} - - <:tab - class="flex-1" - name="top_albums_last_365_days" - phx-click={JS.push("set_period", value: %{period: "last_365_days"})} - phx-target={@myself} - > - {gettext("1y")} - - <:tab - class="flex-1" - name="top_albums_all_time" - phx-click={JS.push("set_period", value: %{period: "all_time"})} - phx-target={@myself} - > - {gettext("All time")} - - - <.async_result :let={top_albums} assign={@top_albums}> - <:loading> -
- <.loading /> -
- - <.top_albums_by_period albums={top_albums} /> - - -
- """ - end - - defp name_from_period(period), do: "top_albums_#{period}" - - @impl true - def mount(socket) do - {:ok, - socket - |> assign(:period, :last_7_days)} - end - - @impl true - def update(assigns, socket) do - {:ok, - socket - |> assign(assigns) - |> assign_top_albums()} - end - - @impl true - def handle_event("set_period", %{"period" => period}, socket) do - {:noreply, - socket - |> assign(:period, String.to_existing_atom(period)) - |> assign_top_albums()} - end - - attr :albums, :list, required: true - - defp top_albums_by_period(assigns) do - ~H""" -
-
+ + <:item :let={albums}>
-
-
+ + """ end - defp assign_top_albums(socket) do - %{timezone: timezone, period: period} = socket.assigns - current_time = DateTime.utc_now() - - assign_async( - socket, - :top_albums, - fn -> - top_albums = - ListeningStats.get_top_albums_by_period( - limit: 10, - current_time: current_time, - timezone: timezone, - period: period - ) - - {:ok, %{top_albums: top_albums}} - end, - reset: true - ) - end - defp navigate_to_record(album) do cond do album.collected_record_id -> diff --git a/lib/music_library_web/live/stats_live/top_artists.ex b/lib/music_library_web/live/stats_live/top_artists.ex index 5b4d84c2..c1bfe3e7 100644 --- a/lib/music_library_web/live/stats_live/top_artists.ex +++ b/lib/music_library_web/live/stats_live/top_artists.ex @@ -1,112 +1,28 @@ defmodule MusicLibraryWeb.StatsLive.TopArtists do - use MusicLibraryWeb, :live_component + use MusicLibraryWeb, :html import MusicLibraryWeb.RecordComponents, only: [artist_image: 1] alias MusicLibrary.ListeningStats + alias MusicLibraryWeb.StatsLive.TopByPeriod + + attr :id, :string, required: true + attr :timezone, :string, required: true + attr :last_updated_uts, :any def live(assigns) do ~H""" - <.live_component module={__MODULE__} {assigns} id={@id} /> - """ - end - - @impl true - def render(assigns) do - ~H""" -
-

- {gettext("Top Artists")} -

- <.tabs class="mt-4"> - <.tabs_list active_tab={name_from_period(@period)} variant="segmented" size="xs"> - <:tab - class="flex-1" - name="top_artists_last_7_days" - phx-click={JS.push("set_period", value: %{period: "last_7_days"})} - phx-target={@myself} - > - {gettext("7d")} - - <:tab - class="flex-1" - name="top_artists_last_30_days" - phx-click={JS.push("set_period", value: %{period: "last_30_days"})} - phx-target={@myself} - > - {gettext("30d")} - - <:tab - class="flex-1" - name="top_artists_last_90_days" - phx-click={JS.push("set_period", value: %{period: "last_90_days"})} - phx-target={@myself} - > - {gettext("90d")} - - <:tab - class="flex-1" - name="top_artists_last_365_days" - phx-click={JS.push("set_period", value: %{period: "last_365_days"})} - phx-target={@myself} - > - {gettext("1y")} - - <:tab - class="flex-1" - name="top_artists_all_time" - phx-click={JS.push("set_period", value: %{period: "all_time"})} - phx-target={@myself} - > - {gettext("All time")} - - - <.async_result :let={top_artists} assign={@top_artists}> - <:loading> -
- <.loading /> -
- - <.top_artists_by_period artists={top_artists} /> - - -
- """ - end - - defp name_from_period(period), do: "top_artists_#{period}" - - @impl true - def mount(socket) do - {:ok, - socket - |> assign(:period, :last_7_days)} - end - - @impl true - def update(assigns, socket) do - {:ok, - socket - |> assign(assigns) - |> assign_top_artists()} - end - - @impl true - def handle_event("set_period", %{"period" => period}, socket) do - {:noreply, - socket - |> assign(:period, String.to_existing_atom(period)) - |> assign_top_artists()} - end - - attr :artists, :list, required: true - - def top_artists_by_period(assigns) do - ~H""" -
-
+ + <:item :let={artists}>
-
-
+ + """ end - - defp assign_top_artists(socket) do - %{timezone: timezone, period: period} = socket.assigns - current_time = DateTime.utc_now() - - assign_async( - socket, - :top_artists, - fn -> - top_artists = - ListeningStats.get_top_artists_by_period( - limit: 10, - current_time: current_time, - timezone: timezone, - period: period - ) - - {:ok, %{top_artists: top_artists}} - end, - reset: true - ) - end end diff --git a/lib/music_library_web/live/stats_live/top_by_period.ex b/lib/music_library_web/live/stats_live/top_by_period.ex new file mode 100644 index 00000000..2b6c82de --- /dev/null +++ b/lib/music_library_web/live/stats_live/top_by_period.ex @@ -0,0 +1,130 @@ +defmodule MusicLibraryWeb.StatsLive.TopByPeriod do + use MusicLibraryWeb, :live_component + + attr :id, :string, required: true + attr :title, :string, required: true + attr :key, :atom, required: true + attr :fetch_fn, :any, required: true + attr :timezone, :string, required: true + attr :last_updated_uts, :any + + slot :item, required: true + + def live(assigns) do + ~H""" + <.live_component module={__MODULE__} {assigns} id={@id} /> + """ + end + + @impl true + def render(assigns) do + ~H""" +
+

+ {@title} +

+ <.tabs class="mt-4"> + <.tabs_list active_tab={name_from_period(@key, @period)} variant="segmented" size="xs"> + <:tab + class="flex-1" + name={"#{@key}_last_7_days"} + phx-click={JS.push("set_period", value: %{period: "last_7_days"})} + phx-target={@myself} + > + {gettext("7d")} + + <:tab + class="flex-1" + name={"#{@key}_last_30_days"} + phx-click={JS.push("set_period", value: %{period: "last_30_days"})} + phx-target={@myself} + > + {gettext("30d")} + + <:tab + class="flex-1" + name={"#{@key}_last_90_days"} + phx-click={JS.push("set_period", value: %{period: "last_90_days"})} + phx-target={@myself} + > + {gettext("90d")} + + <:tab + class="flex-1" + name={"#{@key}_last_365_days"} + phx-click={JS.push("set_period", value: %{period: "last_365_days"})} + phx-target={@myself} + > + {gettext("1y")} + + <:tab + class="flex-1" + name={"#{@key}_all_time"} + phx-click={JS.push("set_period", value: %{period: "all_time"})} + phx-target={@myself} + > + {gettext("All time")} + + + <.async_result :let={items} assign={assigns[@key]}> + <:loading> +
+ <.loading /> +
+ +
+
+ {render_slot(@item, items)} +
+
+ + +
+ """ + end + + defp name_from_period(key, period), do: "#{key}_#{period}" + + @impl true + def mount(socket) do + {:ok, assign(socket, :period, :last_7_days)} + end + + @impl true + def update(assigns, socket) do + {:ok, + socket + |> assign(assigns) + |> assign_data()} + end + + @impl true + def handle_event("set_period", %{"period" => period}, socket) do + {:noreply, + socket + |> assign(:period, String.to_existing_atom(period)) + |> assign_data()} + end + + defp assign_data(socket) do + %{timezone: timezone, period: period, key: key, fetch_fn: fetch_fn} = socket.assigns + current_time = DateTime.utc_now() + + assign_async( + socket, + key, + fn -> + items = + fetch_fn.( + limit: 10, + current_time: current_time, + timezone: timezone, + period: period + ) + + {:ok, %{key => items}} + end, + reset: true + ) + end +end diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index 853e6fd3..65ba6535 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -851,8 +851,7 @@ msgstr "" msgid "Top Artists" msgstr "" -#: lib/music_library_web/live/stats_live/top_albums.ex -#: lib/music_library_web/live/stats_live/top_artists.ex +#: lib/music_library_web/live/stats_live/top_by_period.ex #, elixir-autogen, elixir-format msgid "All time" msgstr "" @@ -1304,26 +1303,22 @@ msgstr "" msgid "Read" msgstr "" -#: lib/music_library_web/live/stats_live/top_albums.ex -#: lib/music_library_web/live/stats_live/top_artists.ex +#: lib/music_library_web/live/stats_live/top_by_period.ex #, elixir-autogen, elixir-format msgid "1y" msgstr "" -#: lib/music_library_web/live/stats_live/top_albums.ex -#: lib/music_library_web/live/stats_live/top_artists.ex +#: lib/music_library_web/live/stats_live/top_by_period.ex #, elixir-autogen, elixir-format msgid "30d" msgstr "" -#: lib/music_library_web/live/stats_live/top_albums.ex -#: lib/music_library_web/live/stats_live/top_artists.ex +#: lib/music_library_web/live/stats_live/top_by_period.ex #, elixir-autogen, elixir-format msgid "7d" msgstr "" -#: lib/music_library_web/live/stats_live/top_albums.ex -#: lib/music_library_web/live/stats_live/top_artists.ex +#: lib/music_library_web/live/stats_live/top_by_period.ex #, elixir-autogen, elixir-format msgid "90d" msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index 677b9039..3a117ed6 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -851,8 +851,7 @@ msgstr "" msgid "Top Artists" msgstr "" -#: lib/music_library_web/live/stats_live/top_albums.ex -#: lib/music_library_web/live/stats_live/top_artists.ex +#: lib/music_library_web/live/stats_live/top_by_period.ex #, elixir-autogen, elixir-format msgid "All time" msgstr "" @@ -1304,26 +1303,22 @@ msgstr "" msgid "Read" msgstr "" -#: lib/music_library_web/live/stats_live/top_albums.ex -#: lib/music_library_web/live/stats_live/top_artists.ex +#: lib/music_library_web/live/stats_live/top_by_period.ex #, elixir-autogen, elixir-format msgid "1y" msgstr "" -#: lib/music_library_web/live/stats_live/top_albums.ex -#: lib/music_library_web/live/stats_live/top_artists.ex +#: lib/music_library_web/live/stats_live/top_by_period.ex #, elixir-autogen, elixir-format, fuzzy msgid "30d" msgstr "" -#: lib/music_library_web/live/stats_live/top_albums.ex -#: lib/music_library_web/live/stats_live/top_artists.ex +#: lib/music_library_web/live/stats_live/top_by_period.ex #, elixir-autogen, elixir-format msgid "7d" msgstr "" -#: lib/music_library_web/live/stats_live/top_albums.ex -#: lib/music_library_web/live/stats_live/top_artists.ex +#: lib/music_library_web/live/stats_live/top_by_period.ex #, elixir-autogen, elixir-format, fuzzy msgid "90d" msgstr ""