defmodule MusicLibraryWeb.FormComponent do use MusicLibraryWeb, :live_component import MusicLibraryWeb.RecordComponents, only: [format_label: 1, type_label: 1, release_label: 1, release_summary: 1] alias MusicLibrary.Records alias MusicLibrary.Records.{Cover, Record} @impl true def mount(socket) do {:ok, socket |> allow_upload(:cover_data, accept: ~w(.jpg .jpeg .png .webp), max_entries: 1)} end @impl true def render(assigns) do ~H"""

{Record.artist_names(@record)}

{@record.title}

<.simple_form for={@form} id="record-form" phx-target={@myself} phx-change="validate" phx-auto-recover="recover_form" phx-submit="save" > <.input field={@form[:title]} label={gettext("Title")} />
<.select field={@form[:type]} label={gettext("Type")} options={types_with_labels()} /> <.select field={@form[:format]} label={gettext("Format")} options={formats_with_labels()} />
<.input class="font-mono" field={@form[:musicbrainz_id]} label={gettext("MusicBrainz ID")} /> <.select field={@form[:selected_release_id]} label={gettext("Selected Release")} options={selected_release_id_options(@record)} > <:option :let={{_label, value}}> <.release_option release={Records.Record.find_release(@record, value)} />
<.input field={@form[:release_date]} label={gettext("Release Date")} /> <.date_time_picker :if={@show_purchased_at} field={@form[:purchased_at]} display_format="%B %-d, %Y at %I:%M %p" label={gettext("Purchased at")} />
<.label for="dominant_colors"> {gettext("Dominant Colors")}
{String.upcase(color)}
<.label for={@uploads.cover_data.ref}> {gettext("Cover art")}
{@record.title} <.live_img_preview :for={entry <- @uploads.cover_data.entries} class="mx-auto size-24" entry={entry} />
<%= for entry <- @uploads.cover_data.entries do %> {entry.progress}% <% end %>

{gettext("or drag and drop")}

{gettext("PNG, JPG, WEBP up to 8MB")}

<:actions>
<.button variant="solid" class="w-full md:w-auto" phx-disable-with={gettext("Saving...")}> {gettext("Save")}
""" end attr :release, :map, required: true defp release_option(assigns) do ~H"""
<.release_summary release={@release} class="w-74" />
""" end @impl true def update(%{record: record} = assigns, socket) do {:ok, socket |> assign(assigns) |> assign_new(:form, fn -> to_form(Records.change_record(record)) end)} end @impl true def handle_event("validate", %{"record" => record_params}, socket) do changeset = Records.change_record(socket.assigns.record, record_params) {:noreply, assign(socket, form: to_form(changeset, action: :validate))} end def handle_event("save", %{"record" => record_params}, socket) do uploaded_covers = consume_uploaded_entries(socket, :cover_data, fn %{path: path}, _entry -> {:ok, File.read!(path)} end) save_record(socket, record_params, uploaded_covers) end def handle_event("recover_form", params, socket) do handle_event("validate", params, socket) end defp save_record(socket, record_params, uploaded_covers) do params = case uploaded_covers do [] -> record_params [cover_data] -> {:ok, thumb_data} = Cover.resize(cover_data) Map.put(record_params, "cover_data", thumb_data) end case Records.update_record(socket.assigns.record, params) do {:ok, record} -> notify_parent({:saved, record}) {:noreply, socket |> put_flash(:info, gettext("Record updated successfully")) |> push_patch(to: socket.assigns.patch)} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign(socket, form: to_form(changeset))} end end def formats_with_labels do Enum.map(Records.Record.formats(), fn f -> {format_label(f), f} end) end def types_with_labels do Enum.map(Records.Record.types(), fn t -> {type_label(t), t} end) end defp selected_release_id_options(record) do record |> Records.Record.releases() |> Enum.map(fn release -> { release_label(release), release.id } end) end defp notify_parent(msg), do: send(self(), {__MODULE__, msg}) end