159 lines
4.4 KiB
Elixir
159 lines
4.4 KiB
Elixir
|
|
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
|
||
|
|
</.link>
|
||
|
|
|
||
|
|
<.header>
|
||
|
|
{if @live_action == :new, do: "New page", else: "Page settings"}
|
||
|
|
</.header>
|
||
|
|
|
||
|
|
<.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" />
|
||
|
|
|
||
|
|
<div :if={@form[:show_in_nav].value == true} class="space-y-4 pl-6">
|
||
|
|
<.input field={@form[:nav_label]} label="Nav label" />
|
||
|
|
<.input field={@form[:nav_position]} type="number" label="Nav position" />
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="flex gap-3">
|
||
|
|
<.button type="submit" phx-disable-with="Saving...">
|
||
|
|
{if @live_action == :new, do: "Create page", else: "Save settings"}
|
||
|
|
</.button>
|
||
|
|
<.link navigate={~p"/admin/pages"} class="admin-btn admin-btn-ghost">
|
||
|
|
Cancel
|
||
|
|
</.link>
|
||
|
|
</div>
|
||
|
|
</.form>
|
||
|
|
"""
|
||
|
|
end
|
||
|
|
end
|