defmodule BerrypodWeb.Admin.Pages.CustomForm do use BerrypodWeb, :live_view alias Berrypod.Pages alias Berrypod.Pages.Page @impl true def mount(params, _session, socket) do {:ok, apply_action(socket, socket.assigns.live_action, params)} end defp apply_action(socket, :new, _params) do changeset = Page.custom_changeset(%Page{}, %{}) socket |> assign(:page_title, "New page") |> assign(:page_struct, %Page{}) |> assign(:slug_touched, false) |> assign(:form, to_form(changeset)) end defp apply_action(socket, :edit, %{"slug" => slug}) do case Pages.get_page_struct(slug) do %Page{type: "custom"} = page -> changeset = Page.custom_changeset(page, %{}) socket |> assign(:page_title, "#{page.title} settings") |> assign(:page_struct, page) |> assign(:slug_touched, true) |> assign(:form, to_form(changeset)) _ -> socket |> put_flash(:error, "Page not found") |> push_navigate(to: ~p"/admin/pages") end end @impl true def handle_event("validate", %{"page" => params}, socket) do params = maybe_slugify(params, socket) form = socket.assigns.page_struct |> Page.custom_changeset(params) |> Map.put(:action, :validate) |> to_form() slug_touched = socket.assigns.slug_touched || (params["slug"] && params["slug"] != "") {:noreply, assign(socket, form: form, slug_touched: slug_touched)} end @impl true def handle_event("save", %{"page" => params}, socket) do save_page(socket, socket.assigns.live_action, params) end defp save_page(socket, :new, params) do case Pages.create_custom_page(params) do {:ok, page} -> {:noreply, socket |> put_flash(:info, "Page created") |> push_navigate(to: ~p"/admin/pages/#{page.slug}")} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign(socket, form: to_form(changeset))} end end defp save_page(socket, :edit, params) do case Pages.update_custom_page(socket.assigns.page_struct, params) do {:ok, page} -> {:noreply, socket |> put_flash(:info, "Page settings saved") |> push_navigate(to: ~p"/admin/pages/#{page.slug}")} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign(socket, form: to_form(changeset))} end end # Auto-generate slug from title when creating and slug hasn't been manually edited defp maybe_slugify(params, %{assigns: %{live_action: :new, slug_touched: false}}) do case params["title"] do title when is_binary(title) and title != "" -> slug = title |> String.downcase() |> String.replace(~r/[^a-z0-9\s-]/, "") |> String.trim() |> String.replace(~r/\s+/, "-") |> String.replace(~r/-+/, "-") |> String.trim("-") Map.put(params, "slug", slug) _ -> params end end defp maybe_slugify(params, _socket), do: params @impl true def render(assigns) do ~H""" <.link navigate={~p"/admin/pages"} class="text-sm font-normal text-base-content/60 hover:underline" > ← Pages <.header> {if @live_action == :new, do: "New page", else: "Page settings"} <.form for={@form} id="custom-page-form" phx-change="validate" phx-submit="save" class="mt-6 space-y-6" style="max-width: 32rem;" > <.input field={@form[:title]} label="Title" /> <.input field={@form[:slug]} label="URL slug" /> <.input field={@form[:meta_description]} type="textarea" label="Meta description" phx-no-feedback /> <.input field={@form[:published]} type="checkbox" label="Published" /> <.input field={@form[:show_in_nav]} type="checkbox" label="Show in navigation" />