berrypod/lib/berrypod_web/theme_hook.ex
jamey 64f083d271
All checks were successful
deploy / deploy (push) Successful in 1m31s
improve setup UX: password field, setup hook, checklist banners, theme tweaks
- add password field and required shop name to setup wizard
- extract SetupHook for DRY redirect to /setup when no admin exists
- add ?from=checklist param to checklist hrefs with contextual banner on
  email settings and theme pages for easy return to dashboard
- remove email warning banner from admin layout (checklist covers it)
- make email a required checklist item (no longer optional)
- add DevReset module for wiping dev data without restart
- rename "Theme Studio" to "Theme", drop subtitle
- lower theme editor side-by-side breakpoint from 64em to 48em
- clean up login/registration pages (remove dead registration_open code)
- fix settings.put_secret to invalidate cache after write

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:41:08 +00:00

97 lines
3.0 KiB
Elixir

defmodule BerrypodWeb.ThemeHook do
@moduledoc """
LiveView on_mount hook for theme settings, CSS, and media assigns.
Mounted in the public_shop live_session alongside CartHook.
Eliminates the identical theme-loading boilerplate from every shop LiveView.
## Actions
- `:mount_theme` — loads theme settings, CSS, and media assigns
- `:require_site_live` — redirects unauthenticated visitors to /coming-soon
when the shop is not live
"""
import Phoenix.Component, only: [assign: 3]
alias Berrypod.{Products, Settings, Media}
alias Berrypod.Theme.{CSSCache, CSSGenerator}
@default_header_nav [
%{"label" => "Home", "href" => "/", "slug" => "home"},
%{
"label" => "Shop",
"href" => "/collections/all",
"slug" => "collection",
"active_slugs" => ["collection", "pdp"]
},
%{"label" => "About", "href" => "/about", "slug" => "about"},
%{"label" => "Contact", "href" => "/contact", "slug" => "contact"}
]
@default_footer_nav [
%{"label" => "Delivery & returns", "href" => "/delivery", "slug" => "delivery"},
%{"label" => "Privacy policy", "href" => "/privacy", "slug" => "privacy"},
%{"label" => "Terms of service", "href" => "/terms", "slug" => "terms"},
%{"label" => "Contact", "href" => "/contact", "slug" => "contact"}
]
def default_header_nav, do: @default_header_nav
def default_footer_nav, do: @default_footer_nav
def on_mount(:mount_theme, _params, _session, socket) do
theme_settings = Settings.get_theme_settings()
generated_css =
case CSSCache.get() do
{:ok, css} ->
css
:miss ->
css = CSSGenerator.generate(theme_settings, &BerrypodWeb.Endpoint.static_path/1)
CSSCache.put(css)
css
end
socket =
socket
|> assign(:theme_settings, theme_settings)
|> assign(:site_name, Settings.site_name())
|> assign(:site_description, Settings.site_description())
|> assign(:generated_css, generated_css)
|> assign(:logo_image, Media.get_logo())
|> assign(:header_image, Media.get_header())
|> assign(:categories, Products.list_categories())
|> assign(:mode, :shop)
|> assign(
:is_admin,
!!(socket.assigns[:current_scope] && socket.assigns.current_scope.user)
)
|> assign(:header_nav_items, load_nav("header_nav", @default_header_nav))
|> assign(:footer_nav_items, load_nav("footer_nav", @default_footer_nav))
{:cont, socket}
end
def on_mount(:require_site_live, _params, _session, socket) do
cond do
Settings.site_live?() ->
{:cont, socket}
# mount_current_scope runs first, so current_scope is already validated
socket.assigns[:current_scope] && socket.assigns.current_scope.user ->
{:cont, socket}
true ->
{:halt, Phoenix.LiveView.redirect(socket, to: "/coming-soon")}
end
end
defp load_nav(key, default) do
case Settings.get_setting(key) do
items when is_list(items) -> items
_ -> default
end
end
end