Can add wishlisted records to a record set

This commit is contained in:
Claudio Ortolina
2026-02-06 15:03:18 +00:00
parent de9ba50534
commit c01c528580
5 changed files with 156 additions and 81 deletions
@@ -21,4 +21,13 @@ defmodule MusicLibrary.RecordSets.RecordSet do
|> cast(attrs, [:name, :description])
|> validate_required([:name])
end
def count_by_status(record_set) do
record_set.items
|> Enum.frequencies_by(fn item ->
if item.record.purchased_at, do: :collected, else: :wishlisted
end)
|> Map.new()
|> Map.put(:total, Enum.count(record_set.items))
end
end
@@ -43,7 +43,7 @@
{record_set.name}
</h2>
<span class="ml-2 text-xs text-zinc-500 dark:text-zinc-400">
{ngettext("1 record", "%{count} records", length(record_set.items))}
{gettext("%{collected}/%{total} records", RecordSet.count_by_status(record_set))}
</span>
</header>
<article
@@ -92,9 +92,26 @@
<div class="flex flex-wrap items-start gap-3 md:overflow-x-auto pb-2">
<div
:for={item <- record_set.items}
class="flex-none w-24 sm:w-32 group relative"
class={[
"flex-none w-24 sm:w-32 group relative",
is_nil(item.record.purchased_at) &&
"opacity-60 hover:opacity-100 transition-opacity"
]}
>
<.link
:if={item.record.purchased_at}
navigate={~p"/collection/#{item.record}"}
>
<MusicLibraryWeb.RecordComponents.record_cover
record={item.record}
class="rounded-lg aspect-square object-cover"
width={256}
/>
</.link>
<.link
:if={!item.record.purchased_at}
navigate={~p"/wishlist/#{item.record}"}
>
<.link navigate={~p"/collection/#{item.record}"}>
<MusicLibraryWeb.RecordComponents.record_cover
record={item.record}
class="rounded-lg aspect-square object-cover"
@@ -107,14 +124,13 @@
placement="bottom-end"
>
<:toggle>
<span class="rounded-full bg-zinc-900/60 p-0.5 cursor-pointer">
<span class="sr-only">{gettext("Actions")}</span>
<.icon
name="hero-ellipsis-vertical"
class="h-4 w-4 text-white"
class="size-5 text-zinc-800 dark:text-zinc-200 cursor-pointer"
aria-hidden="true"
data-slot="icon"
/>
</span>
</:toggle>
<.dropdown_button
:if={item.position > 0}
@@ -3,6 +3,7 @@ defmodule MusicLibraryWeb.RecordSetLive.RecordPicker do
alias MusicLibrary.Collection
alias MusicLibrary.Records.Record
alias MusicLibrary.Wishlist
import MusicLibraryWeb.RecordComponents, only: [format_label: 1, type_label: 1]
@@ -15,7 +16,7 @@ defmodule MusicLibraryWeb.RecordSetLive.RecordPicker do
{@title}
</h1>
<p class="text-sm text-zinc-500 dark:text-zinc-400 mt-1">
{gettext("Search your collection to add a record to this set.")}
{gettext("Search your records to add a record to this set.")}
</p>
</header>
<form
@@ -38,18 +39,42 @@ defmodule MusicLibraryWeb.RecordSetLive.RecordPicker do
/>
</form>
<ul
<div
:if={@query != ""}
class="mt-4 divide-y divide-zinc-100 dark:divide-zinc-700 max-h-96 overflow-y-auto"
class="mt-4 max-h-96 overflow-y-auto"
>
<li
:if={@results == []}
<p
:if={@collected_results == [] and @wishlisted_results == []}
class="py-4 text-center text-sm text-zinc-500 dark:text-zinc-400"
>
{gettext("No records found")}
</li>
</p>
<div :if={@collected_results != []}>
<h3 class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400 mb-1">
{gettext("Collected")}
</h3>
<ul class="divide-y divide-zinc-100 dark:divide-zinc-700">
<.record_result :for={record <- @collected_results} record={record} myself={@myself} />
</ul>
</div>
<div :if={@wishlisted_results != []} class={[@collected_results != [] && "mt-4"]}>
<h3 class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400 mb-1">
{gettext("Wishlisted")}
</h3>
<ul class="divide-y divide-zinc-100 dark:divide-zinc-700">
<.record_result :for={record <- @wishlisted_results} record={record} myself={@myself} />
</ul>
</div>
</div>
</div>
"""
end
defp record_result(assigns) do
~H"""
<li
:for={record <- @results}
role="option"
class={[
"flex items-center gap-3 py-3 px-2 hover:bg-zinc-50 dark:hover:bg-zinc-800 cursor-pointer rounded-lg",
@@ -57,25 +82,25 @@ defmodule MusicLibraryWeb.RecordSetLive.RecordPicker do
]}
phx-click="add_record"
phx-target={@myself}
phx-value-record-id={record.id}
phx-value-record-id={@record.id}
>
<div class="w-12 flex-none">
<MusicLibraryWeb.RecordComponents.record_cover
record={record}
record={@record}
class="rounded aspect-square object-cover"
width={96}
/>
</div>
<div class="min-w-0 flex-auto">
<p class="text-sm font-medium text-zinc-900 dark:text-zinc-100 truncate">
{record.title}
{@record.title}
</p>
<p class="text-xs text-zinc-500 dark:text-zinc-400 truncate">
{Record.artist_names(record)}
{Record.artist_names(@record)}
</p>
<p class="mt-1 text-xs leading-5 text-zinc-500 dark:text-zinc-400">
{Record.format_release_date(record.release_date)} · {type_label(record.type)} · {format_label(
record.format
{Record.format_release_date(@record.release_date)} · {type_label(@record.type)} · {format_label(
@record.format
)}
</p>
</div>
@@ -88,8 +113,6 @@ defmodule MusicLibraryWeb.RecordSetLive.RecordPicker do
/>
</div>
</li>
</ul>
</div>
"""
end
@@ -102,27 +125,39 @@ defmodule MusicLibraryWeb.RecordSetLive.RecordPicker do
socket
|> assign(assigns)
|> assign(:query, "")
|> assign(:results, [])
|> assign(:collected_results, [])
|> assign(:wishlisted_results, [])
|> assign(:existing_record_ids, existing_record_ids)}
end
@impl true
def handle_event("search", %{"query" => query}, socket) do
results =
{collected, wishlisted} =
if String.trim(query) == "" do
[]
{[], []}
else
reject = fn record ->
MapSet.member?(socket.assigns.existing_record_ids, record.id)
end
collected =
query
|> Collection.search_records(limit: 20)
|> Enum.reject(fn record ->
MapSet.member?(socket.assigns.existing_record_ids, record.id)
end)
|> Enum.reject(reject)
wishlisted =
query
|> Wishlist.search_records(limit: 20)
|> Enum.reject(reject)
{collected, wishlisted}
end
{:noreply,
socket
|> assign(:query, query)
|> assign(:results, results)}
|> assign(:collected_results, collected)
|> assign(:wishlisted_results, wishlisted)}
end
def handle_event("add_record", %{"record-id" => record_id}, socket) do
@@ -132,8 +167,10 @@ defmodule MusicLibraryWeb.RecordSetLive.RecordPicker do
{:ok, updated_set} ->
existing_record_ids = MapSet.put(socket.assigns.existing_record_ids, record_id)
results =
Enum.reject(socket.assigns.results, fn record -> record.id == record_id end)
reject = fn record -> record.id == record_id end
collected_results = Enum.reject(socket.assigns.collected_results, reject)
wishlisted_results = Enum.reject(socket.assigns.wishlisted_results, reject)
notify_parent({:added, updated_set})
put_toast!(:info, gettext("Record added to set"))
@@ -142,7 +179,8 @@ defmodule MusicLibraryWeb.RecordSetLive.RecordPicker do
socket
|> assign(:record_set, updated_set)
|> assign(:existing_record_ids, existing_record_ids)
|> assign(:results, results)}
|> assign(:collected_results, collected_results)
|> assign(:wishlisted_results, wishlisted_results)}
{:error, _changeset} ->
put_toast!(:error, gettext("Could not add record to set"))
+12 -6
View File
@@ -270,6 +270,7 @@ msgid "Choose which format to import"
msgstr ""
#: lib/music_library_web/components/barcode_scanner.ex
#: lib/music_library_web/live/record_set_live/record_picker.ex
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
#: lib/music_library_web/live/stats_live/index.html.heex
#, elixir-autogen, elixir-format
@@ -277,6 +278,7 @@ msgid "Collected"
msgstr ""
#: lib/music_library_web/components/barcode_scanner.ex
#: lib/music_library_web/live/record_set_live/record_picker.ex
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
#: lib/music_library_web/live/stats_live/index.html.heex
#, elixir-autogen, elixir-format
@@ -395,7 +397,6 @@ msgid "On Tour"
msgstr ""
#: lib/music_library_web/components/record_components.ex
#: lib/music_library_web/live/record_set_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "1 record"
msgid_plural "%{count} records"
@@ -1778,11 +1779,6 @@ msgstr ""
msgid "Save Set"
msgstr ""
#: lib/music_library_web/live/record_set_live/record_picker.ex
#, elixir-autogen, elixir-format
msgid "Search your collection to add a record to this set."
msgstr ""
#: lib/music_library_web/components/layouts/app.html.heex
#, elixir-autogen, elixir-format
msgid "Sets"
@@ -1797,3 +1793,13 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "e.g. Favorites, Road Trip, Sunday Morning"
msgstr ""
#: lib/music_library_web/live/record_set_live/record_picker.ex
#, elixir-autogen, elixir-format
msgid "Search your records to add a record to this set."
msgstr ""
#: lib/music_library_web/live/record_set_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "%{collected}/%{total} records"
msgstr ""
+12 -6
View File
@@ -270,6 +270,7 @@ msgid "Choose which format to import"
msgstr ""
#: lib/music_library_web/components/barcode_scanner.ex
#: lib/music_library_web/live/record_set_live/record_picker.ex
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
#: lib/music_library_web/live/stats_live/index.html.heex
#, elixir-autogen, elixir-format
@@ -277,6 +278,7 @@ msgid "Collected"
msgstr ""
#: lib/music_library_web/components/barcode_scanner.ex
#: lib/music_library_web/live/record_set_live/record_picker.ex
#: lib/music_library_web/live/scrobbled_tracks_live/index.html.heex
#: lib/music_library_web/live/stats_live/index.html.heex
#, elixir-autogen, elixir-format
@@ -395,7 +397,6 @@ msgid "On Tour"
msgstr ""
#: lib/music_library_web/components/record_components.ex
#: lib/music_library_web/live/record_set_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "1 record"
msgid_plural "%{count} records"
@@ -1778,11 +1779,6 @@ msgstr ""
msgid "Save Set"
msgstr ""
#: lib/music_library_web/live/record_set_live/record_picker.ex
#, elixir-autogen, elixir-format
msgid "Search your collection to add a record to this set."
msgstr ""
#: lib/music_library_web/components/layouts/app.html.heex
#, elixir-autogen, elixir-format
msgid "Sets"
@@ -1797,3 +1793,13 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "e.g. Favorites, Road Trip, Sunday Morning"
msgstr ""
#: lib/music_library_web/live/record_set_live/record_picker.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Search your records to add a record to this set."
msgstr ""
#: lib/music_library_web/live/record_set_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "%{collected}/%{total} records"
msgstr ""