add legal page editor integration and media library polish
Some checks failed
deploy / deploy (push) Has been cancelled

Legal pages (privacy, delivery, terms) now auto-populate content from
shop settings on mount, show auto-generated vs customised badges, and
have a regenerate button. Theme editor gains alt text fields for logo,
header, and icon images. Image picker in page builder now has an upload
button and alt text warning badges. Clearing unused image references
shows an orphan info flash.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-02-28 17:55:02 +00:00
parent 3336b3aa26
commit 93ff66debc
9 changed files with 495 additions and 11 deletions

View File

@@ -252,4 +252,96 @@ defmodule Berrypod.LegalPagesTest do
assert List.last(blocks).type == :closing
end
end
# ---------------------------------------------------------------------------
# regenerate_legal_content/1
# ---------------------------------------------------------------------------
describe "regenerate_legal_content/1" do
test "returns a non-empty string for privacy" do
result = LegalPages.regenerate_legal_content("privacy")
assert is_binary(result)
assert String.length(result) > 100
end
test "returns a non-empty string for delivery" do
result = LegalPages.regenerate_legal_content("delivery")
assert is_binary(result)
assert String.length(result) > 100
end
test "returns a non-empty string for terms" do
result = LegalPages.regenerate_legal_content("terms")
assert is_binary(result)
assert String.length(result) > 100
end
end
# ---------------------------------------------------------------------------
# rich_text_to_plain/1
# ---------------------------------------------------------------------------
describe "rich_text_to_plain/1" do
test "converts headings to markdown-style" do
blocks = [%{type: :heading, text: "Hello"}]
assert LegalPages.rich_text_to_plain(blocks) == "## Hello"
end
test "converts paragraphs as-is" do
blocks = [%{type: :paragraph, text: "Some text here."}]
assert LegalPages.rich_text_to_plain(blocks) == "Some text here."
end
test "converts lists to bullet points" do
blocks = [%{type: :list, items: ["One", "Two", "Three"]}]
assert LegalPages.rich_text_to_plain(blocks) == "• One\n• Two\n• Three"
end
test "converts lead blocks" do
blocks = [%{type: :lead, text: "Important intro"}]
assert LegalPages.rich_text_to_plain(blocks) == "Important intro"
end
test "converts updated_at blocks" do
blocks = [%{type: :updated_at, date: "28 February 2026"}]
assert LegalPages.rich_text_to_plain(blocks) == "Last updated: 28 February 2026"
end
test "joins multiple blocks with double newlines" do
blocks = [
%{type: :heading, text: "Title"},
%{type: :paragraph, text: "Body text."}
]
assert LegalPages.rich_text_to_plain(blocks) == "## Title\n\nBody text."
end
test "skips unknown block types" do
blocks = [
%{type: :heading, text: "Title"},
%{type: :unknown_thing, data: "whatever"},
%{type: :paragraph, text: "Body."}
]
assert LegalPages.rich_text_to_plain(blocks) == "## Title\n\nBody."
end
end
# ---------------------------------------------------------------------------
# legal_slug?/1
# ---------------------------------------------------------------------------
describe "legal_slug?/1" do
test "returns true for legal page slugs" do
assert LegalPages.legal_slug?("privacy")
assert LegalPages.legal_slug?("delivery")
assert LegalPages.legal_slug?("terms")
end
test "returns false for non-legal slugs" do
refute LegalPages.legal_slug?("home")
refute LegalPages.legal_slug?("about")
refute LegalPages.legal_slug?("contact")
end
end
end

View File

@@ -1004,6 +1004,66 @@ defmodule BerrypodWeb.Admin.PagesTest do
end
end
describe "legal page editor" do
setup %{conn: conn, user: user} do
%{conn: log_in_user(conn, user)}
end
test "shows regenerate button for privacy page", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/admin/pages/privacy")
assert has_element?(view, "button[phx-click='regenerate_legal']", "Regenerate")
end
test "shows regenerate button for delivery page", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/admin/pages/delivery")
assert has_element?(view, "button[phx-click='regenerate_legal']", "Regenerate")
end
test "does not show regenerate button for home page", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/admin/pages/home")
refute has_element?(view, "button[phx-click='regenerate_legal']")
end
test "shows auto-generated badge for legal pages on mount", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/admin/pages/privacy")
assert has_element?(view, ".admin-badge-info", "Auto-generated from settings")
end
test "auto-populates content_body on mount for legal pages", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/admin/pages/privacy")
# The content_body block should be expanded to see the content
page = Pages.get_page("privacy")
content_body = Enum.find(page.blocks, &(&1["type"] == "content_body"))
render_click(view, "toggle_expand", %{"id" => content_body["id"]})
html = render(view)
# Should contain generated legal content
assert html =~ "What we collect"
end
test "shows customised badge after manual edit", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/admin/pages/privacy")
page = Pages.get_page("privacy")
content_body = Enum.find(page.blocks, &(&1["type"] == "content_body"))
render_click(view, "toggle_expand", %{"id" => content_body["id"]})
render_change(view, "update_block_settings", %{
"block_id" => content_body["id"],
"block_settings" => %{"content" => "Custom privacy content here"}
})
assert has_element?(view, ".admin-badge", "Customised")
refute has_element?(view, ".admin-badge-info", "Auto-generated from settings")
end
end
defp count_repeater_items(html) do
Regex.scan(~r/class="repeater-item"/, html) |> length()
end