diff --git a/lib/simpleshop_theme_web/controllers/error_html.ex b/lib/simpleshop_theme_web/controllers/error_html.ex index c7f1b34..ec00e84 100644 --- a/lib/simpleshop_theme_web/controllers/error_html.ex +++ b/lib/simpleshop_theme_web/controllers/error_html.ex @@ -6,19 +6,115 @@ defmodule SimpleshopThemeWeb.ErrorHTML do """ use SimpleshopThemeWeb, :html - # If you want to customize your error pages, - # uncomment the embed_templates/1 call below - # and add pages to the error directory: - # - # * lib/simpleshop_theme_web/controllers/error_html/404.html.heex - # * lib/simpleshop_theme_web/controllers/error_html/500.html.heex - # - # embed_templates "error_html/*" + alias SimpleshopTheme.Settings + alias SimpleshopTheme.Settings.ThemeSettings + alias SimpleshopTheme.Media + alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData} + + def render("404.html", assigns) do + render_error_page(assigns, "404", "Page Not Found", + "Sorry, we couldn't find the page you're looking for. Perhaps you've mistyped the URL or the page has been moved.") + end + + def render("500.html", assigns) do + render_error_page(assigns, "500", "Server Error", + "Something went wrong on our end. Please try again later or contact support if the problem persists.") + end - # The default is to render a plain text page based on - # the template name. For example, "404.html" becomes - # "Not Found". def render(template, _assigns) do Phoenix.Controller.status_message_from_template(template) end + + defp render_error_page(assigns, error_code, error_title, error_description) do + # Load theme settings with fallback for error conditions + {theme_settings, generated_css} = load_theme_data() + logo_image = safe_load(&Media.get_logo/0) + header_image = safe_load(&Media.get_header/0) + + preview_data = %{ + products: PreviewData.products(), + categories: PreviewData.categories() + } + + assigns = + assigns + |> Map.put(:theme_settings, theme_settings) + |> Map.put(:generated_css, generated_css) + |> Map.put(:logo_image, logo_image) + |> Map.put(:header_image, header_image) + |> Map.put(:preview_data, preview_data) + |> Map.put(:error_code, error_code) + |> Map.put(:error_title, error_title) + |> Map.put(:error_description, error_description) + |> Map.put(:mode, :shop) + |> Map.put(:cart_items, []) + |> Map.put(:cart_count, 0) + |> Map.put(:cart_subtotal, "£0.00") + + ~H""" + + + + + + <%= @error_code %> - <%= @error_title %> + + + + +
+ +
+ + + """ + end + + defp load_theme_data do + try 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 + {theme_settings, generated_css} + rescue + _ -> {%ThemeSettings{}, ""} + end + end + + defp safe_load(fun) do + try do + fun.() + rescue + _ -> nil + end + end end diff --git a/lib/simpleshop_theme_web/controllers/error_preview_controller.ex b/lib/simpleshop_theme_web/controllers/error_preview_controller.ex new file mode 100644 index 0000000..98493ae --- /dev/null +++ b/lib/simpleshop_theme_web/controllers/error_preview_controller.ex @@ -0,0 +1,20 @@ +defmodule SimpleshopThemeWeb.ErrorPreviewController do + @moduledoc """ + Development-only controller for previewing error pages. + """ + use SimpleshopThemeWeb, :controller + + def not_found(conn, _params) do + conn + |> put_status(:not_found) + |> put_view(SimpleshopThemeWeb.ErrorHTML) + |> render("404.html") + end + + def server_error(conn, _params) do + conn + |> put_status(:internal_server_error) + |> put_view(SimpleshopThemeWeb.ErrorHTML) + |> render("500.html") + end +end diff --git a/lib/simpleshop_theme_web/live/shop_live/cart.ex b/lib/simpleshop_theme_web/live/shop_live/cart.ex new file mode 100644 index 0000000..d3874c1 --- /dev/null +++ b/lib/simpleshop_theme_web/live/shop_live/cart.ex @@ -0,0 +1,68 @@ +defmodule SimpleshopThemeWeb.ShopLive.Cart do + use SimpleshopThemeWeb, :live_view + + alias SimpleshopTheme.Settings + alias SimpleshopTheme.Media + alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, 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() + + # For now, use preview data for cart items + # In a real implementation, this would come from session/database + cart_page_items = PreviewData.cart_items() + cart_page_subtotal = Enum.reduce(cart_page_items, 0, fn item, acc -> + acc + item.product.price * item.quantity + end) + + 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(:cart_page_items, cart_page_items) + |> assign(:cart_page_subtotal, cart_page_subtotal) + |> assign(:mode, :shop) + |> assign(:cart_items, PreviewData.cart_drawer_items()) + |> assign(:cart_count, length(cart_page_items)) + |> assign(:cart_subtotal, format_subtotal(cart_page_subtotal)) + + {:ok, socket} + end + + @impl true + def render(assigns) do + ~H""" + + """ + end + + defp format_subtotal(subtotal_pence) do + "£#{Float.round(subtotal_pence / 100, 2)}" + end +end diff --git a/lib/simpleshop_theme_web/router.ex b/lib/simpleshop_theme_web/router.ex index 84bed60..9e31189 100644 --- a/lib/simpleshop_theme_web/router.ex +++ b/lib/simpleshop_theme_web/router.ex @@ -31,6 +31,7 @@ defmodule SimpleshopThemeWeb.Router do live "/contact", ShopLive.Contact, :index live "/products", ShopLive.Products, :index live "/products/:id", ShopLive.ProductShow, :show + live "/cart", ShopLive.Cart, :index end end @@ -62,6 +63,10 @@ defmodule SimpleshopThemeWeb.Router do live_dashboard "/dashboard", metrics: SimpleshopThemeWeb.Telemetry forward "/mailbox", Plug.Swoosh.MailboxPreview + + # Preview error pages + get "/errors/404", SimpleshopThemeWeb.ErrorPreviewController, :not_found + get "/errors/500", SimpleshopThemeWeb.ErrorPreviewController, :server_error end end diff --git a/test/simpleshop_theme_web/controllers/error_html_test.exs b/test/simpleshop_theme_web/controllers/error_html_test.exs index 04a4a0a..b5e4f17 100644 --- a/test/simpleshop_theme_web/controllers/error_html_test.exs +++ b/test/simpleshop_theme_web/controllers/error_html_test.exs @@ -4,11 +4,17 @@ defmodule SimpleshopThemeWeb.ErrorHTMLTest do # Bring render_to_string/4 for testing custom views import Phoenix.Template, only: [render_to_string: 4] - test "renders 404.html" do - assert render_to_string(SimpleshopThemeWeb.ErrorHTML, "404", "html", []) == "Not Found" + test "renders 404.html with themed page" do + html = render_to_string(SimpleshopThemeWeb.ErrorHTML, "404", "html", []) + assert html =~ "404" + assert html =~ "Page Not Found" + assert html =~ "shop-root" end - test "renders 500.html" do - assert render_to_string(SimpleshopThemeWeb.ErrorHTML, "500", "html", []) == "Internal Server Error" + test "renders 500.html with themed page" do + html = render_to_string(SimpleshopThemeWeb.ErrorHTML, "500", "html", []) + assert html =~ "500" + assert html =~ "Server Error" + assert html =~ "shop-root" end end