@@ -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"""
|
||||
<div>
|
||||
<h1 class="text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
|
||||
{gettext("Top Albums")}
|
||||
</h1>
|
||||
<.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>
|
||||
<: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>
|
||||
<: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>
|
||||
<: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>
|
||||
<: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")}
|
||||
</:tab>
|
||||
</.tabs_list>
|
||||
<.async_result :let={top_albums} assign={@top_albums}>
|
||||
<:loading>
|
||||
<div class="h-182 flex items-center justify-center">
|
||||
<.loading />
|
||||
</div>
|
||||
</:loading>
|
||||
<.top_albums_by_period albums={top_albums} />
|
||||
</.async_result>
|
||||
</.tabs>
|
||||
</div>
|
||||
"""
|
||||
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"""
|
||||
<div class="mt-4 p-4 bg-white dark:bg-zinc-800 rounded-md shadow-sm">
|
||||
<div class="space-y-2">
|
||||
<TopByPeriod.live
|
||||
id={@id}
|
||||
timezone={@timezone}
|
||||
last_updated_uts={@last_updated_uts}
|
||||
title={gettext("Top Albums")}
|
||||
key={:top_albums}
|
||||
fetch_fn={&ListeningStats.get_top_albums_by_period/1}
|
||||
>
|
||||
<:item :let={albums}>
|
||||
<div
|
||||
:for={album <- @albums}
|
||||
:for={album <- albums}
|
||||
phx-click={navigate_to_record(album)}
|
||||
class={[
|
||||
"flex items-center space-x-3 p-2",
|
||||
@@ -151,33 +67,11 @@ defmodule MusicLibraryWeb.StatsLive.TopAlbums do
|
||||
{album.play_count}
|
||||
</.badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</:item>
|
||||
</TopByPeriod.live>
|
||||
"""
|
||||
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 ->
|
||||
|
||||
@@ -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"""
|
||||
<div>
|
||||
<h1 class="text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
|
||||
{gettext("Top Artists")}
|
||||
</h1>
|
||||
<.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>
|
||||
<: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>
|
||||
<: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>
|
||||
<: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>
|
||||
<: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")}
|
||||
</:tab>
|
||||
</.tabs_list>
|
||||
<.async_result :let={top_artists} assign={@top_artists}>
|
||||
<:loading>
|
||||
<div class="h-182 flex items-center justify-center">
|
||||
<.loading />
|
||||
</div>
|
||||
</:loading>
|
||||
<.top_artists_by_period artists={top_artists} />
|
||||
</.async_result>
|
||||
</.tabs>
|
||||
</div>
|
||||
"""
|
||||
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"""
|
||||
<div class="mt-4 p-4 bg-white dark:bg-zinc-800 rounded-md shadow-sm">
|
||||
<div class="space-y-2">
|
||||
<TopByPeriod.live
|
||||
id={@id}
|
||||
timezone={@timezone}
|
||||
last_updated_uts={@last_updated_uts}
|
||||
title={gettext("Top Artists")}
|
||||
key={:top_artists}
|
||||
fetch_fn={&ListeningStats.get_top_artists_by_period/1}
|
||||
>
|
||||
<:item :let={artists}>
|
||||
<div
|
||||
:for={artist <- @artists}
|
||||
:for={artist <- artists}
|
||||
phx-click={
|
||||
artist.musicbrainz_id != "" &&
|
||||
JS.navigate(~p"/artists/#{artist.musicbrainz_id}")
|
||||
@@ -139,30 +55,8 @@ defmodule MusicLibraryWeb.StatsLive.TopArtists do
|
||||
{artist.play_count}
|
||||
</.badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</:item>
|
||||
</TopByPeriod.live>
|
||||
"""
|
||||
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
|
||||
|
||||
@@ -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"""
|
||||
<div>
|
||||
<h1 class="text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
|
||||
{@title}
|
||||
</h1>
|
||||
<.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>
|
||||
<: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>
|
||||
<: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>
|
||||
<: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>
|
||||
<:tab
|
||||
class="flex-1"
|
||||
name={"#{@key}_all_time"}
|
||||
phx-click={JS.push("set_period", value: %{period: "all_time"})}
|
||||
phx-target={@myself}
|
||||
>
|
||||
{gettext("All time")}
|
||||
</:tab>
|
||||
</.tabs_list>
|
||||
<.async_result :let={items} assign={assigns[@key]}>
|
||||
<:loading>
|
||||
<div class="h-182 flex items-center justify-center">
|
||||
<.loading />
|
||||
</div>
|
||||
</:loading>
|
||||
<div class="mt-4 p-4 bg-white dark:bg-zinc-800 rounded-md shadow-sm">
|
||||
<div class="space-y-2">
|
||||
{render_slot(@item, items)}
|
||||
</div>
|
||||
</div>
|
||||
</.async_result>
|
||||
</.tabs>
|
||||
</div>
|
||||
"""
|
||||
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
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
Reference in New Issue
Block a user