refactor: extract ThemeHook to eliminate mount duplication

on_mount hook assigns theme_settings, generated_css, logo_image,
header_image, and mode for all public shop LiveViews. Removes
~70 lines of identical boilerplate and 18 unused aliases across
7 LiveViews.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey 2026-02-08 11:59:33 +00:00
parent dd19281f4f
commit e6d4fce656
9 changed files with 50 additions and 182 deletions

View File

@ -2,38 +2,10 @@ defmodule SimpleshopThemeWeb.ShopLive.Cart do
use SimpleshopThemeWeb, :live_view use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Cart alias SimpleshopTheme.Cart
alias SimpleshopTheme.Settings
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator}
@impl true @impl true
def mount(_params, _session, socket) do def mount(_params, _session, socket) do
theme_settings = Settings.get_theme_settings() {:ok, assign(socket, :page_title, "Cart")}
generated_css =
case CSSCache.get() do
{:ok, css} ->
css
:miss ->
css = CSSGenerator.generate(theme_settings)
CSSCache.put(css)
css
end
logo_image = Media.get_logo()
header_image = Media.get_header()
socket =
socket
|> assign(:page_title, "Cart")
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
|> assign(:logo_image, logo_image)
|> assign(:header_image, header_image)
|> assign(:mode, :shop)
{:ok, socket}
end end
@impl true @impl true

View File

@ -1,27 +1,10 @@
defmodule SimpleshopThemeWeb.ShopLive.CheckoutSuccess do defmodule SimpleshopThemeWeb.ShopLive.CheckoutSuccess do
use SimpleshopThemeWeb, :live_view use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.{Orders, Settings, Media} alias SimpleshopTheme.Orders
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator}
@impl true @impl true
def mount(%{"session_id" => session_id}, _session, socket) do def mount(%{"session_id" => session_id}, _session, socket) do
theme_settings = Settings.get_theme_settings()
generated_css =
case CSSCache.get() do
{:ok, css} ->
css
:miss ->
css = CSSGenerator.generate(theme_settings)
CSSCache.put(css)
css
end
logo_image = Media.get_logo()
header_image = Media.get_header()
order = Orders.get_order_by_stripe_session(session_id) order = Orders.get_order_by_stripe_session(session_id)
# Subscribe to order status updates (webhook may arrive after redirect) # Subscribe to order status updates (webhook may arrive after redirect)
@ -32,10 +15,7 @@ defmodule SimpleshopThemeWeb.ShopLive.CheckoutSuccess do
# Clear the cart after successful checkout # Clear the cart after successful checkout
socket = socket =
if order && connected?(socket) do if order && connected?(socket) do
empty_cart = [] SimpleshopThemeWeb.CartHook.broadcast_and_update(socket, [])
socket
|> SimpleshopThemeWeb.CartHook.broadcast_and_update(empty_cart)
else else
socket socket
end end
@ -43,11 +23,6 @@ defmodule SimpleshopThemeWeb.ShopLive.CheckoutSuccess do
socket = socket =
socket socket
|> assign(:page_title, "Order confirmed") |> assign(:page_title, "Order confirmed")
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
|> assign(:logo_image, logo_image)
|> assign(:header_image, header_image)
|> assign(:mode, :shop)
|> assign(:order, order) |> assign(:order, order)
{:ok, socket} {:ok, socket}

View File

@ -1,9 +1,7 @@
defmodule SimpleshopThemeWeb.ShopLive.Collection do defmodule SimpleshopThemeWeb.ShopLive.Collection do
use SimpleshopThemeWeb, :live_view use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Settings alias SimpleshopTheme.Theme.PreviewData
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
@sort_options [ @sort_options [
{"featured", "Featured"}, {"featured", "Featured"},
@ -16,29 +14,8 @@ defmodule SimpleshopThemeWeb.ShopLive.Collection do
@impl true @impl true
def mount(_params, _session, socket) do def mount(_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)
CSSCache.put(css)
css
end
logo_image = Media.get_logo()
header_image = Media.get_header()
socket = socket =
socket socket
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
|> assign(:logo_image, logo_image)
|> assign(:header_image, header_image)
|> assign(:mode, :shop)
|> assign(:categories, PreviewData.categories()) |> assign(:categories, PreviewData.categories())
|> assign(:sort_options, @sort_options) |> assign(:sort_options, @sort_options)
|> assign(:current_sort, "featured") |> assign(:current_sort, "featured")

View File

@ -1,38 +1,9 @@
defmodule SimpleshopThemeWeb.ShopLive.Contact do defmodule SimpleshopThemeWeb.ShopLive.Contact do
use SimpleshopThemeWeb, :live_view use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Settings
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator}
@impl true @impl true
def mount(_params, _session, socket) do def mount(_params, _session, socket) do
theme_settings = Settings.get_theme_settings() {:ok, assign(socket, :page_title, "Contact")}
generated_css =
case CSSCache.get() do
{:ok, css} ->
css
:miss ->
css = CSSGenerator.generate(theme_settings)
CSSCache.put(css)
css
end
logo_image = Media.get_logo()
header_image = Media.get_header()
socket =
socket
|> assign(:page_title, "Contact")
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
|> assign(:logo_image, logo_image)
|> assign(:header_image, header_image)
|> assign(:mode, :shop)
{:ok, socket}
end end
@impl true @impl true

View File

@ -1,32 +1,10 @@
defmodule SimpleshopThemeWeb.ShopLive.Content do defmodule SimpleshopThemeWeb.ShopLive.Content do
use SimpleshopThemeWeb, :live_view use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.{Settings, Media} alias SimpleshopTheme.Theme.PreviewData
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
@impl true @impl true
def mount(_params, _session, socket) do def mount(_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)
CSSCache.put(css)
css
end
socket =
socket
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
|> assign(:logo_image, Media.get_logo())
|> assign(:header_image, Media.get_header())
|> assign(:mode, :shop)
{:ok, socket} {:ok, socket}
end end

View File

@ -1,28 +1,10 @@
defmodule SimpleshopThemeWeb.ShopLive.Home do defmodule SimpleshopThemeWeb.ShopLive.Home do
use SimpleshopThemeWeb, :live_view use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Settings alias SimpleshopTheme.Theme.PreviewData
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
@impl true @impl true
def mount(_params, _session, socket) do def mount(_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)
CSSCache.put(css)
css
end
logo_image = Media.get_logo()
header_image = Media.get_header()
preview_data = %{ preview_data = %{
products: PreviewData.products(), products: PreviewData.products(),
categories: PreviewData.categories() categories: PreviewData.categories()
@ -31,12 +13,7 @@ defmodule SimpleshopThemeWeb.ShopLive.Home do
socket = socket =
socket socket
|> assign(:page_title, "Home") |> assign(:page_title, "Home")
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
|> assign(:logo_image, logo_image)
|> assign(:header_image, header_image)
|> assign(:preview_data, preview_data) |> assign(:preview_data, preview_data)
|> assign(:mode, :shop)
{:ok, socket} {:ok, socket}
end end

View File

@ -2,28 +2,10 @@ defmodule SimpleshopThemeWeb.ShopLive.ProductShow do
use SimpleshopThemeWeb, :live_view use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Cart alias SimpleshopTheme.Cart
alias SimpleshopTheme.Settings alias SimpleshopTheme.Theme.PreviewData
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
@impl true @impl true
def mount(%{"id" => id}, _session, socket) do def mount(%{"id" => id}, _session, socket) do
theme_settings = Settings.get_theme_settings()
generated_css =
case CSSCache.get() do
{:ok, css} ->
css
:miss ->
css = CSSGenerator.generate(theme_settings)
CSSCache.put(css)
css
end
logo_image = Media.get_logo()
header_image = Media.get_header()
products = PreviewData.products() products = PreviewData.products()
# Find product by slug or ID (real products use slugs, mock data uses string IDs) # Find product by slug or ID (real products use slugs, mock data uses string IDs)
@ -53,15 +35,10 @@ defmodule SimpleshopThemeWeb.ShopLive.ProductShow do
socket = socket =
socket socket
|> assign(:page_title, product.name) |> assign(:page_title, product.name)
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
|> assign(:logo_image, logo_image)
|> assign(:header_image, header_image)
|> assign(:product, product) |> assign(:product, product)
|> assign(:gallery_images, gallery_images) |> assign(:gallery_images, gallery_images)
|> assign(:related_products, related_products) |> assign(:related_products, related_products)
|> assign(:quantity, 1) |> assign(:quantity, 1)
|> assign(:mode, :shop)
|> assign(:option_types, option_types) |> assign(:option_types, option_types)
|> assign(:variants, variants) |> assign(:variants, variants)
|> assign(:selected_options, selected_options) |> assign(:selected_options, selected_options)

View File

@ -32,7 +32,10 @@ defmodule SimpleshopThemeWeb.Router do
live_session :public_shop, live_session :public_shop,
layout: {SimpleshopThemeWeb.Layouts, :shop}, layout: {SimpleshopThemeWeb.Layouts, :shop},
on_mount: [{SimpleshopThemeWeb.CartHook, :mount_cart}] do on_mount: [
{SimpleshopThemeWeb.ThemeHook, :mount_theme},
{SimpleshopThemeWeb.CartHook, :mount_cart}
] do
live "/", ShopLive.Home, :index live "/", ShopLive.Home, :index
live "/about", ShopLive.Content, :about live "/about", ShopLive.Content, :about
live "/delivery", ShopLive.Content, :delivery live "/delivery", ShopLive.Content, :delivery

View File

@ -0,0 +1,38 @@
defmodule SimpleshopThemeWeb.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.
"""
import Phoenix.Component, only: [assign: 3]
alias SimpleshopTheme.{Settings, Media}
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator}
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)
CSSCache.put(css)
css
end
socket =
socket
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
|> assign(:logo_image, Media.get_logo())
|> assign(:header_image, Media.get_header())
|> assign(:mode, :shop)
{:cont, socket}
end
end