integrate R module and add url editor ui
Replaces hardcoded paths with R module throughout: - Shop components: layout nav, cart, product links - Controllers: cart, checkout, contact, seo, order lookup - Shop pages: collection, product, search, checkout success, etc. - Site context: nav item url resolution Admin URL management: - Settings page: prefix editor with validation feedback - Page renderer: url_editor component for page URLs - CSS for url editor styling Test updates for cache isolation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -270,10 +270,11 @@ defmodule BerrypodWeb.PageEditorHook do
|
||||
end
|
||||
|
||||
# Initialize settings form from current page if not already set
|
||||
# Only custom pages have editable settings (meta_description, published, etc.)
|
||||
# Init settings form for pages with editable settings
|
||||
# Custom pages: all settings editable
|
||||
# System pages: only url_slug editable (except home)
|
||||
socket =
|
||||
if is_nil(socket.assigns[:settings_form]) && socket.assigns[:page] &&
|
||||
socket.assigns.page[:type] == "custom" do
|
||||
if is_nil(socket.assigns[:settings_form]) && socket.assigns[:page] do
|
||||
init_settings_form(socket)
|
||||
else
|
||||
socket
|
||||
@@ -930,14 +931,14 @@ defmodule BerrypodWeb.PageEditorHook do
|
||||
# Catch-all for unknown theme actions
|
||||
defp handle_theme_action(_action, _params, socket), do: {:halt, socket}
|
||||
|
||||
# ── Settings editing actions (custom page settings) ────────────────
|
||||
# ── Settings editing actions (page settings) ────────────────
|
||||
|
||||
# Validate page settings form (live as-you-type)
|
||||
defp handle_settings_action("validate_page", %{"page" => params}, socket) do
|
||||
page = socket.assigns.page
|
||||
|
||||
# Only allow editing custom pages
|
||||
if page && page.type == "custom" do
|
||||
# Allow editing for custom pages (all fields) or system pages (url_slug only)
|
||||
if page && page.type in ["custom", "system"] do
|
||||
socket =
|
||||
socket
|
||||
|> assign(:settings_form, params)
|
||||
@@ -954,43 +955,127 @@ defmodule BerrypodWeb.PageEditorHook do
|
||||
defp handle_settings_action("save_page", %{"page" => params}, socket) do
|
||||
page = socket.assigns.page
|
||||
|
||||
# Only allow editing custom pages
|
||||
if page && page.type == "custom" do
|
||||
# Normalize checkbox fields (unchecked checkboxes aren't sent)
|
||||
params =
|
||||
params
|
||||
|> Map.put_new("published", "false")
|
||||
|> Map.put_new("show_in_nav", "false")
|
||||
cond do
|
||||
# Custom pages: save all settings including url_slug
|
||||
page && page.type == "custom" ->
|
||||
save_custom_page_settings(socket, page, params)
|
||||
|
||||
old_slug = page.slug
|
||||
# System pages with url_prefix (collections, products, orders)
|
||||
page && page.type == "system" && params["url_prefix"] ->
|
||||
save_system_page_url_prefix(socket, page, params["url_prefix"])
|
||||
|
||||
# Fetch the Page struct from DB (assigns.page may be a map from cache)
|
||||
page_struct = Pages.get_page_struct(page.slug)
|
||||
# System pages: only save url_slug (other fields are read-only)
|
||||
page && page.type == "system" && params["url_slug"] ->
|
||||
save_system_page_url_slug(socket, page, params["url_slug"])
|
||||
|
||||
case Pages.update_custom_page(page_struct, params) do
|
||||
{:ok, updated_page} ->
|
||||
# Reinitialize form from saved page
|
||||
true ->
|
||||
{:halt, socket}
|
||||
end
|
||||
end
|
||||
|
||||
defp handle_settings_action(_action, _params, socket), do: {:halt, socket}
|
||||
|
||||
defp save_custom_page_settings(socket, page, params) do
|
||||
# Normalize checkbox fields (unchecked checkboxes aren't sent)
|
||||
params =
|
||||
params
|
||||
|> Map.put_new("published", "false")
|
||||
|> Map.put_new("show_in_nav", "false")
|
||||
|
||||
old_slug = page.slug
|
||||
|
||||
# Fetch the Page struct from DB (assigns.page may be a map from cache)
|
||||
page_struct = Pages.get_page_struct(page.slug)
|
||||
|
||||
# Handle url_slug change separately to ensure redirects are created
|
||||
url_slug = params["url_slug"]
|
||||
old_url_slug = page[:url_slug]
|
||||
|
||||
# First update the main page settings
|
||||
case Pages.update_custom_page(page_struct, params) do
|
||||
{:ok, updated_page} ->
|
||||
# If url_slug changed, handle redirect creation
|
||||
socket =
|
||||
if url_slug != old_url_slug do
|
||||
Pages.update_page_url_slug(updated_page, url_slug)
|
||||
# Reload page to get updated url_slug
|
||||
updated_page = Pages.get_page(updated_page.slug)
|
||||
assign(socket, :page, updated_page)
|
||||
else
|
||||
assign(socket, :page, updated_page)
|
||||
end
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(:settings_form, nil)
|
||||
|> assign(:settings_dirty, false)
|
||||
|> assign(:settings_save_status, :saved)
|
||||
|
||||
# Reinit form with new page values
|
||||
socket = init_settings_form(socket)
|
||||
|
||||
# If slug changed, redirect to new URL
|
||||
socket =
|
||||
if updated_page.slug != old_slug do
|
||||
push_navigate(socket, to: "/#{updated_page.slug}")
|
||||
else
|
||||
socket
|
||||
end
|
||||
|
||||
{:halt, socket}
|
||||
|
||||
{:error, _changeset} ->
|
||||
socket = assign(socket, :settings_save_status, :error)
|
||||
{:halt, socket}
|
||||
end
|
||||
end
|
||||
|
||||
defp save_system_page_url_slug(socket, page, url_slug) do
|
||||
case Pages.update_page_url_slug(page.slug, url_slug) do
|
||||
{:ok, _updated} ->
|
||||
# Reload page from cache to get updated data
|
||||
updated_page = Pages.get_page(page.slug)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(:page, updated_page)
|
||||
|> assign(:settings_form, nil)
|
||||
|> assign(:settings_dirty, false)
|
||||
|> assign(:settings_save_status, :saved)
|
||||
|
||||
socket = init_settings_form(socket)
|
||||
{:halt, socket}
|
||||
|
||||
{:error, _} ->
|
||||
socket = assign(socket, :settings_save_status, :error)
|
||||
{:halt, socket}
|
||||
end
|
||||
end
|
||||
|
||||
# Save URL prefix for prefixed pages (collection, pdp, orders)
|
||||
defp save_system_page_url_prefix(socket, page, new_prefix) do
|
||||
# Determine the prefix type based on the page slug
|
||||
prefix_type =
|
||||
case page.slug do
|
||||
"collection" -> :collections
|
||||
"pdp" -> :products
|
||||
"orders" -> :orders
|
||||
"order_detail" -> :orders
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
if prefix_type do
|
||||
case Settings.update_url_prefix(prefix_type, new_prefix) do
|
||||
{:ok, _} ->
|
||||
socket =
|
||||
socket
|
||||
|> assign(:page, updated_page)
|
||||
|> assign(:settings_form, nil)
|
||||
|> assign(:settings_dirty, false)
|
||||
|> assign(:settings_save_status, :saved)
|
||||
|
||||
# Reinit form with new page values
|
||||
socket = init_settings_form(socket)
|
||||
|
||||
# If slug changed, redirect to new URL
|
||||
socket =
|
||||
if updated_page.slug != old_slug do
|
||||
push_navigate(socket, to: "/#{updated_page.slug}")
|
||||
else
|
||||
socket
|
||||
end
|
||||
|
||||
{:halt, socket}
|
||||
|
||||
{:error, _changeset} ->
|
||||
{:error, _reason} ->
|
||||
socket = assign(socket, :settings_save_status, :error)
|
||||
{:halt, socket}
|
||||
end
|
||||
@@ -999,9 +1084,6 @@ defmodule BerrypodWeb.PageEditorHook do
|
||||
end
|
||||
end
|
||||
|
||||
# Catch-all for unknown settings actions
|
||||
defp handle_settings_action(_action, _params, socket), do: {:halt, socket}
|
||||
|
||||
# --- Site tab event handlers ---
|
||||
|
||||
defp handle_site_action("update", %{"site" => site_params}, socket) do
|
||||
@@ -1266,13 +1348,33 @@ defmodule BerrypodWeb.PageEditorHook do
|
||||
defp has_settings_changed?(page, params) do
|
||||
page.title != (params["title"] || "") or
|
||||
page.slug != (params["slug"] || "") or
|
||||
(page[:url_slug] || "") != (params["url_slug"] || "") or
|
||||
(page.meta_description || "") != (params["meta_description"] || "") or
|
||||
to_string(page.published) != (params["published"] || "false") or
|
||||
to_string(page.show_in_nav) != (params["show_in_nav"] || "false") or
|
||||
(page.nav_label || "") != (params["nav_label"] || "") or
|
||||
to_string(page.nav_position || 0) != (params["nav_position"] || "0")
|
||||
to_string(page.nav_position || 0) != (params["nav_position"] || "0") or
|
||||
has_prefix_changed?(page, params)
|
||||
end
|
||||
|
||||
# Check if URL prefix changed for prefixed pages
|
||||
defp has_prefix_changed?(page, params) do
|
||||
case params["url_prefix"] do
|
||||
nil ->
|
||||
false
|
||||
|
||||
new_prefix ->
|
||||
prefix_type = prefix_type_for_page(page.slug)
|
||||
prefix_type != nil and BerrypodWeb.R.prefix(prefix_type) != new_prefix
|
||||
end
|
||||
end
|
||||
|
||||
defp prefix_type_for_page("collection"), do: :collections
|
||||
defp prefix_type_for_page("pdp"), do: :products
|
||||
defp prefix_type_for_page("orders"), do: :orders
|
||||
defp prefix_type_for_page("order_detail"), do: :orders
|
||||
defp prefix_type_for_page(_), do: nil
|
||||
|
||||
# Initialize settings form from page values
|
||||
defp init_settings_form(socket) do
|
||||
page = socket.assigns.page
|
||||
@@ -1280,6 +1382,7 @@ defmodule BerrypodWeb.PageEditorHook do
|
||||
form = %{
|
||||
"title" => page.title || "",
|
||||
"slug" => page.slug || "",
|
||||
"url_slug" => page[:url_slug] || "",
|
||||
"meta_description" => page.meta_description || "",
|
||||
"published" => to_string(page.published),
|
||||
"show_in_nav" => to_string(page.show_in_nav),
|
||||
@@ -1506,6 +1609,15 @@ defmodule BerrypodWeb.PageEditorHook do
|
||||
defp save_all_tabs(socket) do
|
||||
socket
|
||||
|> maybe_save_page()
|
||||
|> maybe_save_settings()
|
||||
|> maybe_finish_save()
|
||||
end
|
||||
|
||||
# If settings save triggered a navigation, don't overwrite the socket
|
||||
defp maybe_finish_save(%{redirected: {:live, _, _}} = socket), do: socket
|
||||
|
||||
defp maybe_finish_save(socket) do
|
||||
socket
|
||||
|> maybe_save_theme()
|
||||
|> maybe_save_site()
|
||||
|> assign(:editor_save_status, :saved)
|
||||
@@ -1537,6 +1649,124 @@ defmodule BerrypodWeb.PageEditorHook do
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_save_settings(socket) do
|
||||
if socket.assigns[:settings_dirty] do
|
||||
page = socket.assigns.page
|
||||
params = socket.assigns[:settings_form] || %{}
|
||||
|
||||
cond do
|
||||
# Custom pages: save all settings including url_slug
|
||||
page && page.type == "custom" ->
|
||||
do_save_custom_page_settings(socket, page, params)
|
||||
|
||||
# System pages with url_prefix (collections, products, orders)
|
||||
page && page.type == "system" && params["url_prefix"] ->
|
||||
do_save_system_page_url_prefix(socket, page, params["url_prefix"])
|
||||
|
||||
# System pages: only save url_slug
|
||||
page && page.type == "system" && params["url_slug"] ->
|
||||
do_save_system_page_url_slug(socket, page, params["url_slug"])
|
||||
|
||||
true ->
|
||||
socket
|
||||
end
|
||||
else
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
defp do_save_custom_page_settings(socket, page, params) do
|
||||
params =
|
||||
params
|
||||
|> Map.put_new("published", "false")
|
||||
|> Map.put_new("show_in_nav", "false")
|
||||
|
||||
page_struct = Pages.get_page_struct(page.slug)
|
||||
url_slug = params["url_slug"]
|
||||
old_url_slug = page[:url_slug]
|
||||
|
||||
case Pages.update_custom_page(page_struct, params) do
|
||||
{:ok, updated_page} ->
|
||||
if url_slug != old_url_slug do
|
||||
Pages.update_page_url_slug(updated_page, url_slug)
|
||||
end
|
||||
|
||||
updated_page = Pages.get_page(updated_page.slug)
|
||||
|
||||
socket
|
||||
|> assign(:page, updated_page)
|
||||
|> assign(:settings_form, nil)
|
||||
|> assign(:settings_dirty, false)
|
||||
|> init_settings_form()
|
||||
|
||||
{:error, _changeset} ->
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
defp do_save_system_page_url_slug(socket, page, url_slug) do
|
||||
old_url = Pages.Page.effective_url(page)
|
||||
|
||||
case Pages.update_page_url_slug(page.slug, url_slug) do
|
||||
{:ok, _updated} ->
|
||||
updated_page = Pages.get_page(page.slug)
|
||||
new_url = Pages.Page.effective_url(updated_page)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(:page, updated_page)
|
||||
|> assign(:settings_form, nil)
|
||||
|> assign(:settings_dirty, false)
|
||||
|> init_settings_form()
|
||||
|
||||
# If URL changed, navigate to the new URL
|
||||
if old_url != new_url do
|
||||
push_navigate(socket, to: "/#{new_url}?edit=page")
|
||||
else
|
||||
socket
|
||||
end
|
||||
|
||||
{:error, _reason} ->
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
defp do_save_system_page_url_prefix(socket, page, new_prefix) do
|
||||
prefix_type = prefix_type_for_page(page.slug)
|
||||
|
||||
if prefix_type do
|
||||
old_prefix = BerrypodWeb.R.prefix(prefix_type)
|
||||
|
||||
case Settings.update_url_prefix(prefix_type, new_prefix) do
|
||||
{:ok, _} ->
|
||||
socket =
|
||||
socket
|
||||
|> assign(:settings_form, nil)
|
||||
|> assign(:settings_dirty, false)
|
||||
|
||||
# If prefix changed, navigate to the new URL
|
||||
if old_prefix != new_prefix do
|
||||
# For collection page, navigate to /new-prefix/all
|
||||
new_path =
|
||||
case page.slug do
|
||||
"collection" -> "/#{new_prefix}/all?edit=page"
|
||||
"pdp" -> "/#{new_prefix}?edit=page"
|
||||
_ -> "/#{new_prefix}?edit=page"
|
||||
end
|
||||
|
||||
push_navigate(socket, to: new_path)
|
||||
else
|
||||
socket
|
||||
end
|
||||
|
||||
{:error, _reason} ->
|
||||
socket
|
||||
end
|
||||
else
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_save_theme(socket) do
|
||||
if socket.assigns[:theme_dirty] do
|
||||
case Settings.update_theme_settings(Map.from_struct(socket.assigns.theme_editor_settings)) do
|
||||
|
||||
Reference in New Issue
Block a user