defmodule BerrypodWeb.Admin.Navigation do use BerrypodWeb, :live_view alias Berrypod.{Pages, Settings} alias BerrypodWeb.ThemeHook @impl true def mount(_params, _session, socket) do header_items = load_nav("header_nav", ThemeHook.default_header_nav()) footer_items = load_nav("footer_nav", ThemeHook.default_footer_nav()) custom_pages = Pages.list_custom_pages() {:ok, socket |> assign(:page_title, "Navigation") |> assign(:header_items, header_items) |> assign(:footer_items, footer_items) |> assign(:custom_pages, custom_pages) |> assign(:dirty, false)} end # ── Item manipulation ────────────────────────────────────────── @impl true def handle_event("update_item", params, socket) do section = params["section"] index = String.to_integer(params["index"]) field = params["field"] value = params["value"] items = get_items(socket, section) item = Enum.at(items, index) if item do updated = Map.put(item, field, value) items = List.replace_at(items, index, updated) {:noreply, put_items(socket, section, items)} else {:noreply, socket} end end def handle_event("remove_item", %{"section" => section, "index" => index_str}, socket) do index = String.to_integer(index_str) items = get_items(socket, section) |> List.delete_at(index) {:noreply, put_items(socket, section, items)} end def handle_event( "move_item", %{"section" => section, "index" => index_str, "dir" => dir}, socket ) do index = String.to_integer(index_str) items = get_items(socket, section) target = if dir == "up", do: index - 1, else: index + 1 if target >= 0 and target < length(items) do item = Enum.at(items, index) items = items |> List.delete_at(index) |> List.insert_at(target, item) {:noreply, put_items(socket, section, items)} else {:noreply, socket} end end def handle_event("add_item", %{"section" => section}, socket) do items = get_items(socket, section) ++ [%{"label" => "", "href" => ""}] {:noreply, put_items(socket, section, items)} end def handle_event("add_page", %{"section" => section, "slug" => slug}, socket) do page = Enum.find(socket.assigns.custom_pages, &(&1.slug == slug)) if page do item = %{"label" => page.title, "href" => "/#{page.slug}", "slug" => page.slug} items = get_items(socket, section) ++ [item] {:noreply, put_items(socket, section, items)} else {:noreply, socket} end end # ── Save / reset ─────────────────────────────────────────────── def handle_event("save", _params, socket) do Settings.put_setting("header_nav", socket.assigns.header_items, "json") Settings.put_setting("footer_nav", socket.assigns.footer_items, "json") {:noreply, socket |> assign(:dirty, false) |> put_flash(:info, "Navigation saved")} end def handle_event("reset_defaults", _params, socket) do {:noreply, socket |> assign(:header_items, ThemeHook.default_header_nav()) |> assign(:footer_items, ThemeHook.default_footer_nav()) |> assign(:dirty, true)} end # ── Render ───────────────────────────────────────────────────── @impl true def render(assigns) do ~H""" <.header> Navigation <:subtitle>Configure the links in your shop header and footer.

Unsaved changes

<.nav_section title="Header navigation" section="header" items={@header_items} custom_pages={@custom_pages} /> <.nav_section title="Footer navigation" section="footer" items={@footer_items} custom_pages={@custom_pages} />
""" end defp nav_section(assigns) do ~H"""

{@title}

No items yet.
""" end # ── Helpers ──────────────────────────────────────────────────── defp get_items(socket, "header"), do: socket.assigns.header_items defp get_items(socket, "footer"), do: socket.assigns.footer_items defp put_items(socket, "header", items), do: socket |> assign(:header_items, items) |> assign(:dirty, true) defp put_items(socket, "footer", items), do: socket |> assign(:footer_items, items) |> assign(:dirty, true) defp load_nav(key, default) do case Settings.get_setting(key) do items when is_list(items) -> items _ -> default end end end