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
alias SimpleshopTheme.Cart
alias SimpleshopTheme.Settings
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator}
@impl true
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
|> 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}
{:ok, assign(socket, :page_title, "Cart")}
end
@impl true

View File

@ -1,27 +1,10 @@
defmodule SimpleshopThemeWeb.ShopLive.CheckoutSuccess do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.{Orders, Settings, Media}
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator}
alias SimpleshopTheme.Orders
@impl true
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)
# 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
socket =
if order && connected?(socket) do
empty_cart = []
socket
|> SimpleshopThemeWeb.CartHook.broadcast_and_update(empty_cart)
SimpleshopThemeWeb.CartHook.broadcast_and_update(socket, [])
else
socket
end
@ -43,11 +23,6 @@ defmodule SimpleshopThemeWeb.ShopLive.CheckoutSuccess do
socket =
socket
|> 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)
{:ok, socket}

View File

@ -1,9 +1,7 @@
defmodule SimpleshopThemeWeb.ShopLive.Collection do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Settings
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
alias SimpleshopTheme.Theme.PreviewData
@sort_options [
{"featured", "Featured"},
@ -16,29 +14,8 @@ defmodule SimpleshopThemeWeb.ShopLive.Collection do
@impl true
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
|> 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(:sort_options, @sort_options)
|> assign(:current_sort, "featured")

View File

@ -1,38 +1,9 @@
defmodule SimpleshopThemeWeb.ShopLive.Contact do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Settings
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator}
@impl true
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
|> 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}
{:ok, assign(socket, :page_title, "Contact")}
end
@impl true

View File

@ -1,32 +1,10 @@
defmodule SimpleshopThemeWeb.ShopLive.Content do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.{Settings, Media}
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
alias SimpleshopTheme.Theme.PreviewData
@impl true
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}
end

View File

@ -1,28 +1,10 @@
defmodule SimpleshopThemeWeb.ShopLive.Home do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Settings
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
alias SimpleshopTheme.Theme.PreviewData
@impl true
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 = %{
products: PreviewData.products(),
categories: PreviewData.categories()
@ -31,12 +13,7 @@ defmodule SimpleshopThemeWeb.ShopLive.Home do
socket =
socket
|> 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(:mode, :shop)
{:ok, socket}
end

View File

@ -2,28 +2,10 @@ defmodule SimpleshopThemeWeb.ShopLive.ProductShow do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Cart
alias SimpleshopTheme.Settings
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
alias SimpleshopTheme.Theme.PreviewData
@impl true
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()
# 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
|> 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(:gallery_images, gallery_images)
|> assign(:related_products, related_products)
|> assign(:quantity, 1)
|> assign(:mode, :shop)
|> assign(:option_types, option_types)
|> assign(:variants, variants)
|> assign(:selected_options, selected_options)

View File

@ -32,7 +32,10 @@ defmodule SimpleshopThemeWeb.Router do
live_session :public_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 "/about", ShopLive.Content, :about
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