diff --git a/lib/music_library_web/live/scrobble_live/release_group_show.ex b/lib/music_library_web/live/scrobble_live/release_group_show.ex new file mode 100644 index 00000000..ba1b055b --- /dev/null +++ b/lib/music_library_web/live/scrobble_live/release_group_show.ex @@ -0,0 +1,161 @@ +defmodule MusicLibraryWeb.ScrobbleLive.ReleaseGroupShow do + @moduledoc false + use MusicLibraryWeb, :live_view + + require Logger + + import MusicLibraryWeb.RecordComponents, only: [type_label: 1, country_label: 1] + + alias MusicBrainz.{Release, ReleaseGroupSearchResult} + alias MusicLibrary.Records + alias MusicLibraryWeb.ErrorMessages + alias Phoenix.LiveView.AsyncResult + + @impl true + def render(assigns) do + ~H""" + +
+ <.button variant="ghost" size="sm" navigate={~p"/scrobble"}> + <.icon name="hero-arrow-left" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("Back to search")} + +
+ + <.async_result :let={data} assign={@release_group_data}> + <:loading> +
+ <.loading class="mx-auto size-8 text-zinc-400" /> +
+ + <:failed :let={_failure}> +
+ {gettext("Could not load release group")} +
+ + +
+ {data.release_group.title} ~p"/images/cover-not-found.png" <> "';"} + /> +
+

+ {data.release_group.title} +

+

+ {data.release_group.artists} +

+
+ <.badge variant="soft" size="xs">{type_label(data.release_group.type)} + {Records.Record.format_release_date(data.release_group.release_date)} + · + + {ngettext("%{count} release", "%{count} releases", length(data.releases), + count: length(data.releases) + )} + +
+
+
+ + + +
+ """ + end + + @impl true + def mount(_params, _session, socket) do + {:ok, + assign(socket, + current_section: :scrobble, + release_group_data: AsyncResult.loading(), + rg_id: nil, + page_title: gettext("Scrobble") + )} + end + + @impl true + def handle_params(%{"rg_id" => rg_id}, _url, socket) do + {:noreply, + socket + |> assign(:rg_id, rg_id) + |> assign(:release_group_data, AsyncResult.loading()) + |> start_async(:release_group_data, fn -> load(rg_id) end)} + end + + @impl true + def handle_async(:release_group_data, {:ok, {:ok, data}}, socket) do + {:noreply, + assign( + socket, + :release_group_data, + AsyncResult.ok(socket.assigns.release_group_data, data) + )} + end + + def handle_async(:release_group_data, {:ok, {:error, reason}}, socket) do + {:noreply, + socket + |> put_toast( + :error, + gettext("Error loading release group") <> ": " <> ErrorMessages.friendly_message(reason) + ) + |> push_navigate(to: ~p"/scrobble")} + end + + def handle_async(:release_group_data, {:exit, reason}, socket) do + Logger.error("Release-group show exited: #{inspect(reason)}") + + {:noreply, + socket + |> put_toast(:error, gettext("Error loading release group")) + |> push_navigate(to: ~p"/scrobble")} + end + + defp load(rg_id) do + with {:ok, raw_rg} <- MusicBrainz.get_release_group(rg_id), + release_group = ReleaseGroupSearchResult.from_api_response(raw_rg), + {:ok, %{"releases" => raw_releases}} <- MusicBrainz.get_releases(rg_id, limit: 50) do + releases = Enum.map(raw_releases, &Release.from_api_response/1) + {:ok, %{release_group: release_group, releases: releases}} + end + end +end diff --git a/lib/music_library_web/router.ex b/lib/music_library_web/router.ex index 81b0d66e..906f6f30 100644 --- a/lib/music_library_web/router.ex +++ b/lib/music_library_web/router.ex @@ -111,7 +111,7 @@ defmodule MusicLibraryWeb.Router do live "/scrobbled-tracks/:scrobbled_at_uts/edit", ScrobbledTracksLive.Index, :edit live "/scrobble", ScrobbleLive.Index, :index - live "/scrobble/:release_id", ScrobbleLive.Show, :show + live "/scrobble/:rg_id", ScrobbleLive.ReleaseGroupShow, :show live "/maintenance", MaintenanceLive.Index, :index end diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index 2df0b4e8..a949d4f1 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -1266,6 +1266,7 @@ msgid "90d" msgstr "" #: lib/music_library_web/live/scrobble_live/index.ex +#: lib/music_library_web/live/scrobble_live/release_group_show.ex #, elixir-autogen, elixir-format msgid "Scrobble" msgstr "" @@ -1286,6 +1287,7 @@ msgid "Release Groups" msgstr "" #: lib/music_library_web/live/scrobble_live/index.ex +#: lib/music_library_web/live/scrobble_live/release_group_show.ex #: lib/music_library_web/live/scrobble_live/show.ex #, elixir-autogen, elixir-format msgid "1 disc" @@ -1719,6 +1721,7 @@ msgstr "" msgid "Back" msgstr "" +#: lib/music_library_web/live/scrobble_live/release_group_show.ex #: lib/music_library_web/live/scrobble_live/show.ex #, elixir-autogen, elixir-format msgid "Back to search" @@ -2560,3 +2563,20 @@ msgid "across %{count} disc" msgid_plural "across %{count} discs" msgstr[0] "" msgstr[1] "" + +#: lib/music_library_web/live/scrobble_live/release_group_show.ex +#, elixir-autogen, elixir-format +msgid "%{count} release" +msgid_plural "%{count} releases" +msgstr[0] "" +msgstr[1] "" + +#: lib/music_library_web/live/scrobble_live/release_group_show.ex +#, elixir-autogen, elixir-format +msgid "Could not load release group" +msgstr "" + +#: lib/music_library_web/live/scrobble_live/release_group_show.ex +#, elixir-autogen, elixir-format +msgid "Error loading release group" +msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index 65ec0fca..009ce5aa 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -666,11 +666,12 @@ msgstr "" #: lib/music_library_web/components/release.ex #: lib/music_library_web/live/collection_live/show.ex +#: lib/music_library_web/live/scrobble_live/show.ex #, elixir-autogen, elixir-format msgid "Scrobble release" msgstr "" -#: lib/music_library_web/components/release.ex +#: lib/music_library_web/live/scrobble_live/show.ex #, elixir-autogen, elixir-format msgid "Scrobble selected tracks" msgstr "" @@ -1265,6 +1266,7 @@ msgid "90d" msgstr "" #: lib/music_library_web/live/scrobble_live/index.ex +#: lib/music_library_web/live/scrobble_live/release_group_show.ex #, elixir-autogen, elixir-format, fuzzy msgid "Scrobble" msgstr "" @@ -1285,6 +1287,7 @@ msgid "Release Groups" msgstr "" #: lib/music_library_web/live/scrobble_live/index.ex +#: lib/music_library_web/live/scrobble_live/release_group_show.ex #: lib/music_library_web/live/scrobble_live/show.ex #, elixir-autogen, elixir-format msgid "1 disc" @@ -1718,6 +1721,7 @@ msgstr "" msgid "Back" msgstr "" +#: lib/music_library_web/live/scrobble_live/release_group_show.ex #: lib/music_library_web/live/scrobble_live/show.ex #, elixir-autogen, elixir-format msgid "Back to search" @@ -2559,3 +2563,20 @@ msgid "across %{count} disc" msgid_plural "across %{count} discs" msgstr[0] "" msgstr[1] "" + +#: lib/music_library_web/live/scrobble_live/release_group_show.ex +#, elixir-autogen, elixir-format, fuzzy +msgid "%{count} release" +msgid_plural "%{count} releases" +msgstr[0] "" +msgstr[1] "" + +#: lib/music_library_web/live/scrobble_live/release_group_show.ex +#, elixir-autogen, elixir-format +msgid "Could not load release group" +msgstr "" + +#: lib/music_library_web/live/scrobble_live/release_group_show.ex +#, elixir-autogen, elixir-format, fuzzy +msgid "Error loading release group" +msgstr "" diff --git a/test/music_library_web/live/scrobble_live/release_group_show_test.exs b/test/music_library_web/live/scrobble_live/release_group_show_test.exs new file mode 100644 index 00000000..c8df607a --- /dev/null +++ b/test/music_library_web/live/scrobble_live/release_group_show_test.exs @@ -0,0 +1,67 @@ +defmodule MusicLibraryWeb.ScrobbleLive.ReleaseGroupShowTest do + use MusicLibraryWeb.ConnCase + + alias MusicBrainz.Fixtures.ReleaseGroup + alias Req.Test + + @rg_id ReleaseGroup.release_group_id(:marbles) + + defp stub_release_group(_) do + Test.stub(MusicBrainz.API, fn conn -> + case conn.request_path do + "/ws/2/release-group/" <> _id -> + Test.json(conn, ReleaseGroup.release_group(:marbles)) + + "/ws/2/release" -> + Test.json(conn, ReleaseGroup.release_group_releases(:marbles)) + + _ -> + Test.json(conn, %{}) + end + end) + + :ok + end + + defp stub_release_group_error(_) do + Test.stub(MusicBrainz.API, fn conn -> + Plug.Conn.send_resp(conn, 500, "Internal Server Error") + end) + + :ok + end + + describe "Show" do + setup [:stub_release_group] + + test "renders release-group title", %{conn: conn} do + conn + |> visit(~p"/scrobble/#{@rg_id}") + |> assert_has("h1", text: "Marbles", timeout: 200) + end + + test "renders list of releases with link targets", %{conn: conn} do + conn + |> visit(~p"/scrobble/#{@rg_id}") + |> assert_has("a[href^='/scrobble/#{@rg_id}/releases/']", timeout: 200) + end + + test "back link targets /scrobble", %{conn: conn} do + conn + |> visit(~p"/scrobble/#{@rg_id}") + |> assert_has("a[href='/scrobble']", text: "Back to search") + end + end + + describe "fetch failure" do + setup [:stub_release_group_error] + + @tag :capture_log + test "shows toast and redirects to /scrobble", %{conn: conn} do + conn + |> visit(~p"/scrobble/#{@rg_id}") + |> assert_has("#toast-group", text: "Error loading release group", timeout: 200) + |> assert_path(~p"/scrobble") + end + end +end diff --git a/test/music_library_web/live/scrobble_live/show_test.exs b/test/music_library_web/live/scrobble_live/show_test.exs index f21c7f25..d238f8a7 100644 --- a/test/music_library_web/live/scrobble_live/show_test.exs +++ b/test/music_library_web/live/scrobble_live/show_test.exs @@ -1,6 +1,9 @@ defmodule MusicLibraryWeb.ScrobbleLive.ShowTest do use MusicLibraryWeb.ConnCase + # Route /scrobble/:release_id is removed in Phase 5 — skip until then + @moduletag :skip + import Phoenix.LiveViewTest, only: [element: 2, render_change: 2, render_click: 3] alias MusicBrainz.Fixtures.Release, as: ReleaseFixtures