berrypod/lib/berrypod_web/live/admin/pages/index.ex

163 lines
5.5 KiB
Elixir
Raw Normal View History

defmodule BerrypodWeb.Admin.Pages.Index do
use BerrypodWeb, :live_view
alias Berrypod.Pages
@page_groups [
{"Marketing", ~w(home about contact)},
{"Legal", ~w(delivery privacy terms)},
{"Shop", ~w(collection pdp cart search)},
{"Orders", ~w(checkout_success orders order_detail)},
{"System", ~w(error)}
]
@impl true
def mount(_params, _session, socket) do
pages = Pages.list_pages() |> Map.new(&{&1.slug, &1})
custom_pages = Pages.list_custom_pages()
{:ok,
socket
|> assign(:page_title, "Pages")
|> assign(:pages, pages)
|> assign(:custom_pages, custom_pages)
|> assign(:page_groups, @page_groups)}
end
@impl true
def handle_event("delete_custom_page", %{"slug" => slug}, socket) do
case Pages.get_page_struct(slug) do
%{type: "custom"} = page ->
{:ok, _} = Pages.delete_custom_page(page)
{:noreply,
socket
|> assign(:custom_pages, Pages.list_custom_pages())
|> put_flash(:info, "Page deleted")}
_ ->
{:noreply, put_flash(socket, :error, "Page not found")}
end
end
@impl true
def handle_event("duplicate_custom_page", %{"slug" => slug}, socket) do
case Pages.get_page_struct(slug) do
%{type: "custom"} = page ->
case Pages.duplicate_custom_page(page) do
{:ok, copy} ->
{:noreply,
socket
|> assign(:custom_pages, Pages.list_custom_pages())
|> put_flash(:info, "\"#{copy.title}\" created as draft")}
{:error, _} ->
{:noreply, put_flash(socket, :error, "Failed to duplicate page")}
end
_ ->
{:noreply, put_flash(socket, :error, "Page not found")}
end
end
@impl true
def render(assigns) do
~H"""
<.header>
Pages
<:subtitle>Customise the layout and content of every page on your shop.</:subtitle>
<:actions>
<.link navigate={~p"/admin/pages/new"} class="admin-btn admin-btn-sm admin-btn-primary">
<.icon name="hero-plus" class="size-4" /> New page
</.link>
</:actions>
</.header>
<div class="page-list">
<div :for={{group_name, slugs} <- @page_groups} class="page-group">
<h3 class="page-group-title">{group_name}</h3>
<div class="page-group-cards">
<.link
:for={slug <- slugs}
navigate={~p"/admin/pages/#{slug}"}
class="page-card"
>
<span class="page-card-icon">
<.icon name={page_icon(slug)} class="size-5" />
</span>
<span class="page-card-info">
<span class="page-card-title">{@pages[slug].title}</span>
<span class="page-card-meta">
{length(@pages[slug].blocks)} {if length(@pages[slug].blocks) == 1,
do: "block",
else: "blocks"}
</span>
</span>
<.icon name="hero-chevron-right-mini" class="size-4 page-card-arrow" />
</.link>
</div>
</div>
<div :if={@custom_pages != []} class="page-group">
<h3 class="page-group-title">Custom pages</h3>
<div class="page-group-cards">
<div :for={page <- @custom_pages} class="page-card page-card-custom">
<.link navigate={~p"/admin/pages/#{page.slug}"} class="page-card-link">
<span class="page-card-icon">
<.icon name="hero-document" class="size-5" />
</span>
<span class="page-card-info">
<span class="page-card-title">
{page.title}
<span :if={!page.published} class="admin-badge admin-badge-warning ml-2">
Draft
</span>
</span>
<span class="page-card-meta">
/{page.slug} · {length(page.blocks)} {if length(page.blocks) == 1,
do: "block",
else: "blocks"}
</span>
</span>
<.icon name="hero-chevron-right-mini" class="size-4 page-card-arrow" />
</.link>
<button
phx-click="duplicate_custom_page"
phx-value-slug={page.slug}
class="page-card-action"
aria-label={"Duplicate #{page.title}"}
>
<.icon name="hero-document-duplicate" class="size-4" />
</button>
<button
phx-click="delete_custom_page"
phx-value-slug={page.slug}
data-confirm={"Delete \"#{page.title}\"? This cannot be undone."}
class="page-card-delete"
aria-label={"Delete #{page.title}"}
>
<.icon name="hero-trash" class="size-4" />
</button>
</div>
</div>
</div>
</div>
"""
end
defp page_icon("home"), do: "hero-home"
defp page_icon("about"), do: "hero-user"
defp page_icon("contact"), do: "hero-envelope"
defp page_icon("delivery"), do: "hero-truck"
defp page_icon("privacy"), do: "hero-shield-check"
defp page_icon("terms"), do: "hero-document-text"
defp page_icon("collection"), do: "hero-tag"
defp page_icon("pdp"), do: "hero-cube"
defp page_icon("cart"), do: "hero-shopping-cart"
defp page_icon("search"), do: "hero-magnifying-glass"
defp page_icon("checkout_success"), do: "hero-check-circle"
defp page_icon("orders"), do: "hero-clipboard-document-list"
defp page_icon("order_detail"), do: "hero-clipboard-document"
defp page_icon("error"), do: "hero-exclamation-triangle"
end