a59dd22a18
Import workers now broadcast :records_index_changed on "records:index_changed" after successful import via Records.broadcast_index_changed/0. CollectionLive.Index and WishlistLive.Index subscribe to the topic in mount/3 and reload their record streams on receipt, with a live_action guard to skip reloads when the grid is hidden behind a modal (:import, :barcode_scan). IndexActions.handle_index_changed/1 refreshes total_entries before reloading to keep the pagination bar accurate.
176 lines
5.1 KiB
Elixir
176 lines
5.1 KiB
Elixir
defmodule MusicLibraryWeb.LiveHelpers.IndexActions do
|
|
@moduledoc false
|
|
|
|
import LiveToast, only: [put_toast: 3]
|
|
import Phoenix.Component, only: [assign: 3]
|
|
import Phoenix.LiveView, only: [push_patch: 2, push_navigate: 2, stream: 4, stream_delete: 3]
|
|
import MusicLibraryWeb.Components.Pagination, only: [page_to_offset: 2]
|
|
import MusicLibraryWeb.LiveHelpers.Params
|
|
|
|
use Gettext, backend: MusicLibraryWeb.Gettext
|
|
|
|
alias MusicLibrary.Records
|
|
|
|
@doc """
|
|
Applies the :index action. Reads config from `socket.assigns.index_config`
|
|
for context_module, default_order, allowed_orders, and default_records_list_params.
|
|
|
|
Returns the socket (not wrapped in `{:noreply, ...}`).
|
|
"""
|
|
def apply_index_action(socket, params) do
|
|
config = socket.assigns.index_config
|
|
|
|
query = params["query"] || ""
|
|
order = parse_order(params["order"] || config.default_order, config.allowed_orders)
|
|
total_records = config.context_module.search_records_count(query)
|
|
|
|
record_list_params =
|
|
config.default_records_list_params
|
|
|> merge_query(query)
|
|
|> merge_order(order)
|
|
|> merge_pagination(params, total_records)
|
|
|
|
load_and_assign_records(socket, record_list_params)
|
|
end
|
|
|
|
@doc """
|
|
Applies the :import action. Falls back to :index if the stream hasn't
|
|
been initialized yet.
|
|
|
|
Returns the socket (not wrapped in `{:noreply, ...}`).
|
|
"""
|
|
def apply_import_action(socket, params) do
|
|
config = socket.assigns.index_config
|
|
import_query = params["import_query"] || ""
|
|
|
|
socket
|
|
|> apply_fallback_index(params, :records, fn s, :index, p -> apply_index_action(s, p) end)
|
|
|> assign(:page_title, config.import_page_title)
|
|
|> assign(:import_query, import_query)
|
|
|> assign(:record, nil)
|
|
end
|
|
|
|
@doc """
|
|
Applies the :edit action. Falls back to :index if the stream hasn't
|
|
been initialized yet.
|
|
|
|
Returns the socket (not wrapped in `{:noreply, ...}`).
|
|
"""
|
|
def apply_edit_action(socket, %{"id" => id} = params) do
|
|
config = socket.assigns.index_config
|
|
record = Records.get_record!(id)
|
|
|
|
socket
|
|
|> apply_fallback_index(params, :records, fn s, :index, p -> apply_index_action(s, p) end)
|
|
|> assign(:page_title, record_page_title(record, config))
|
|
|> assign(:record, record)
|
|
end
|
|
|
|
@doc """
|
|
Loads records from the context module and assigns them to the socket stream.
|
|
|
|
Returns the socket (not wrapped in `{:noreply, ...}`).
|
|
"""
|
|
def load_and_assign_records(socket, record_list_params) do
|
|
config = socket.assigns.index_config
|
|
offset = page_to_offset(record_list_params.page, record_list_params.page_size)
|
|
|
|
records =
|
|
config.context_module.search_records(record_list_params.query,
|
|
limit: record_list_params.page_size,
|
|
offset: offset,
|
|
order: record_list_params.order
|
|
)
|
|
|
|
socket
|
|
|> assign(:page_title, config.section_page_title)
|
|
|> assign(:record, nil)
|
|
|> assign(:record_list_params, record_list_params)
|
|
|> stream(:records, records, reset: true)
|
|
end
|
|
|
|
def handle_delete(socket, id) do
|
|
record = Records.get_record!(id)
|
|
{:ok, _} = Records.delete_record(record)
|
|
|
|
{:noreply, stream_delete(socket, :records, record)}
|
|
end
|
|
|
|
def handle_search(socket, query) do
|
|
config = socket.assigns.index_config
|
|
|
|
qs =
|
|
config.default_records_list_params
|
|
|> Map.put(:query, query)
|
|
|> Map.take([:query, :page, :page_size])
|
|
|
|
{:noreply, push_patch(socket, to: config.index_path_fn.(qs))}
|
|
end
|
|
|
|
def handle_cart_imported_single(socket, record) do
|
|
config = socket.assigns.index_config
|
|
|
|
{:noreply,
|
|
socket
|
|
|> put_toast(:info, config.import_success_toast)
|
|
|> push_navigate(to: config.record_path_fn.(record.id))}
|
|
end
|
|
|
|
def handle_cart_imported_async(socket, count) do
|
|
config = socket.assigns.index_config
|
|
|
|
msg =
|
|
ngettext(
|
|
"Importing %{count} record in the background...",
|
|
"Importing %{count} records in the background...",
|
|
count,
|
|
count: count
|
|
)
|
|
|
|
{:noreply,
|
|
socket
|
|
|> put_toast(:info, msg)
|
|
|> push_patch(to: config.base_index_path)}
|
|
end
|
|
|
|
def handle_set_display(socket, mode) do
|
|
mode = parse_mode(mode)
|
|
|
|
{:noreply,
|
|
socket
|
|
|> assign(:display, mode)
|
|
|> load_and_assign_records(socket.assigns.record_list_params)}
|
|
end
|
|
|
|
def handle_record_saved(socket) do
|
|
{:noreply, load_and_assign_records(socket, socket.assigns.record_list_params)}
|
|
end
|
|
|
|
@doc """
|
|
Handles a PubSub notification that records have changed.
|
|
Refreshes total_entries and reloads the record stream using the current parameters.
|
|
"""
|
|
def handle_index_changed(socket) do
|
|
config = socket.assigns.index_config
|
|
params = socket.assigns.record_list_params
|
|
total_records = config.context_module.search_records_count(params.query)
|
|
updated_params = %{params | total_entries: total_records}
|
|
load_and_assign_records(socket, updated_params)
|
|
end
|
|
|
|
defp record_page_title(record, config) do
|
|
Enum.join(
|
|
[
|
|
Records.Record.artist_names(record),
|
|
"-",
|
|
record.title,
|
|
"·",
|
|
gettext("Edit"),
|
|
"·",
|
|
config.section_page_title
|
|
],
|
|
" "
|
|
)
|
|
end
|
|
end
|