add custom page LiveView with catch-all routing
Shop.CustomPage handles /:slug catch-all for CMS pages. Restructured router so the catch-all is last — all admin, auth, setup, and SEO routes defined before the shop scope to prevent interception. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -50,56 +50,7 @@ defmodule BerrypodWeb.Router do
|
||||
plug BerrypodWeb.Plugs.LoadTheme
|
||||
end
|
||||
|
||||
# Public storefront (root level)
|
||||
scope "/", BerrypodWeb do
|
||||
pipe_through [:browser, :shop]
|
||||
|
||||
live_session :coming_soon,
|
||||
layout: {BerrypodWeb.Layouts, :shop},
|
||||
on_mount: [
|
||||
{BerrypodWeb.ThemeHook, :mount_theme}
|
||||
] do
|
||||
live "/coming-soon", Shop.ComingSoon, :index
|
||||
end
|
||||
|
||||
live_session :public_shop,
|
||||
layout: {BerrypodWeb.Layouts, :shop},
|
||||
on_mount: [
|
||||
{BerrypodWeb.UserAuth, :mount_current_scope},
|
||||
{BerrypodWeb.ThemeHook, :mount_theme},
|
||||
{BerrypodWeb.ThemeHook, :require_site_live},
|
||||
{BerrypodWeb.CartHook, :mount_cart},
|
||||
{BerrypodWeb.SearchHook, :mount_search},
|
||||
{BerrypodWeb.AnalyticsHook, :track},
|
||||
{BerrypodWeb.PageEditorHook, :mount_page_editor}
|
||||
] do
|
||||
live "/", Shop.Home, :index
|
||||
live "/about", Shop.Content, :about
|
||||
live "/delivery", Shop.Content, :delivery
|
||||
live "/privacy", Shop.Content, :privacy
|
||||
live "/terms", Shop.Content, :terms
|
||||
live "/contact", Shop.Contact, :index
|
||||
live "/collections/:slug", Shop.Collection, :show
|
||||
live "/products/:id", Shop.ProductShow, :show
|
||||
live "/cart", Shop.Cart, :index
|
||||
live "/search", Shop.Search, :index
|
||||
live "/checkout/success", Shop.CheckoutSuccess, :show
|
||||
live "/orders", Shop.Orders, :index
|
||||
live "/orders/:order_number", Shop.OrderDetail, :show
|
||||
end
|
||||
|
||||
# Checkout (POST — creates Stripe session and redirects)
|
||||
post "/checkout", CheckoutController, :create
|
||||
|
||||
# Order lookup (no-JS fallback for contact page form)
|
||||
post "/contact/lookup", OrderLookupController, :lookup
|
||||
|
||||
# Cart form actions (no-JS fallbacks for LiveView cart events)
|
||||
post "/cart/add", CartController, :add
|
||||
post "/cart/remove", CartController, :remove
|
||||
post "/cart/update", CartController, :update_item
|
||||
post "/cart/country", CartController, :update_country
|
||||
end
|
||||
# ── Routes without the :browser pipeline ──────────────────────────
|
||||
|
||||
# Health check (no auth, no theme loading — for load balancers and uptime monitors)
|
||||
scope "/", BerrypodWeb do
|
||||
@@ -128,13 +79,6 @@ defmodule BerrypodWeb.Router do
|
||||
get "/site.webmanifest", FaviconController, :webmanifest
|
||||
end
|
||||
|
||||
# Cart API (session persistence for LiveView)
|
||||
scope "/api", BerrypodWeb do
|
||||
pipe_through [:browser]
|
||||
|
||||
post "/cart", CartController, :update
|
||||
end
|
||||
|
||||
# SVG recoloring (dynamic — can't be pre-generated to disk)
|
||||
scope "/images", BerrypodWeb do
|
||||
pipe_through :image
|
||||
@@ -161,40 +105,14 @@ defmodule BerrypodWeb.Router do
|
||||
post "/stripe", StripeWebhookController, :handle
|
||||
end
|
||||
|
||||
# LiveDashboard and ErrorTracker behind admin auth (available in all environments)
|
||||
scope "/admin" do
|
||||
pipe_through [:browser, :require_authenticated_user]
|
||||
|
||||
live_dashboard "/dashboard", metrics: BerrypodWeb.Telemetry
|
||||
error_tracker_dashboard("/errors")
|
||||
end
|
||||
|
||||
# Dev-only routes (mailbox preview, error previews)
|
||||
if Application.compile_env(:berrypod, :dev_routes) do
|
||||
scope "/dev" do
|
||||
pipe_through :browser
|
||||
|
||||
forward "/mailbox", Plug.Swoosh.MailboxPreview
|
||||
|
||||
# Preview error pages
|
||||
get "/errors/404", BerrypodWeb.ErrorPreviewController, :not_found
|
||||
get "/errors/500", BerrypodWeb.ErrorPreviewController, :server_error
|
||||
end
|
||||
end
|
||||
|
||||
# Order lookup verification — sets session email then redirects to /orders
|
||||
scope "/", BerrypodWeb do
|
||||
pipe_through [:browser]
|
||||
|
||||
get "/orders/verify/:token", OrderLookupController, :verify
|
||||
get "/unsubscribe/:token", UnsubscribeController, :unsubscribe
|
||||
end
|
||||
# ── Routes with the :browser pipeline ─────────────────────────────
|
||||
# All routes below use :browser. The shop scope with its /:slug
|
||||
# catch-all MUST be last so it doesn't intercept other routes.
|
||||
|
||||
# Setup page — minimal live_session, no theme/cart/search hooks
|
||||
scope "/", BerrypodWeb do
|
||||
pipe_through [:browser]
|
||||
|
||||
# Token-based auto-login after setup/recovery
|
||||
get "/setup/login/:token", SetupController, :login
|
||||
get "/recover/login/:token", SetupController, :recover_login
|
||||
|
||||
@@ -205,7 +123,13 @@ defmodule BerrypodWeb.Router do
|
||||
end
|
||||
end
|
||||
|
||||
## Authentication routes
|
||||
# LiveDashboard and ErrorTracker behind admin auth (available in all environments)
|
||||
scope "/admin" do
|
||||
pipe_through [:browser, :require_authenticated_user]
|
||||
|
||||
live_dashboard "/dashboard", metrics: BerrypodWeb.Telemetry
|
||||
error_tracker_dashboard("/errors")
|
||||
end
|
||||
|
||||
# Admin pages with sidebar layout
|
||||
scope "/admin", BerrypodWeb do
|
||||
@@ -269,4 +193,87 @@ defmodule BerrypodWeb.Router do
|
||||
post "/users/log-in", UserSessionController, :create
|
||||
delete "/users/log-out", UserSessionController, :delete
|
||||
end
|
||||
|
||||
# Order lookup verification — sets session email then redirects to /orders
|
||||
scope "/", BerrypodWeb do
|
||||
pipe_through [:browser]
|
||||
|
||||
get "/orders/verify/:token", OrderLookupController, :verify
|
||||
get "/unsubscribe/:token", UnsubscribeController, :unsubscribe
|
||||
end
|
||||
|
||||
# Dev-only routes (mailbox preview, error previews)
|
||||
if Application.compile_env(:berrypod, :dev_routes) do
|
||||
scope "/dev" do
|
||||
pipe_through :browser
|
||||
|
||||
forward "/mailbox", Plug.Swoosh.MailboxPreview
|
||||
|
||||
# Preview error pages
|
||||
get "/errors/404", BerrypodWeb.ErrorPreviewController, :not_found
|
||||
get "/errors/500", BerrypodWeb.ErrorPreviewController, :server_error
|
||||
end
|
||||
end
|
||||
|
||||
# Cart API (session persistence for LiveView)
|
||||
scope "/api", BerrypodWeb do
|
||||
pipe_through [:browser]
|
||||
|
||||
post "/cart", CartController, :update
|
||||
end
|
||||
|
||||
# Public storefront — MUST be last because /:slug catch-all absorbs
|
||||
# any single-segment path not matched above
|
||||
scope "/", BerrypodWeb do
|
||||
pipe_through [:browser, :shop]
|
||||
|
||||
live_session :coming_soon,
|
||||
layout: {BerrypodWeb.Layouts, :shop},
|
||||
on_mount: [
|
||||
{BerrypodWeb.ThemeHook, :mount_theme}
|
||||
] do
|
||||
live "/coming-soon", Shop.ComingSoon, :index
|
||||
end
|
||||
|
||||
live_session :public_shop,
|
||||
layout: {BerrypodWeb.Layouts, :shop},
|
||||
on_mount: [
|
||||
{BerrypodWeb.UserAuth, :mount_current_scope},
|
||||
{BerrypodWeb.ThemeHook, :mount_theme},
|
||||
{BerrypodWeb.ThemeHook, :require_site_live},
|
||||
{BerrypodWeb.CartHook, :mount_cart},
|
||||
{BerrypodWeb.SearchHook, :mount_search},
|
||||
{BerrypodWeb.AnalyticsHook, :track},
|
||||
{BerrypodWeb.PageEditorHook, :mount_page_editor}
|
||||
] do
|
||||
live "/", Shop.Home, :index
|
||||
live "/about", Shop.Content, :about
|
||||
live "/delivery", Shop.Content, :delivery
|
||||
live "/privacy", Shop.Content, :privacy
|
||||
live "/terms", Shop.Content, :terms
|
||||
live "/contact", Shop.Contact, :index
|
||||
live "/collections/:slug", Shop.Collection, :show
|
||||
live "/products/:id", Shop.ProductShow, :show
|
||||
live "/cart", Shop.Cart, :index
|
||||
live "/search", Shop.Search, :index
|
||||
live "/checkout/success", Shop.CheckoutSuccess, :show
|
||||
live "/orders", Shop.Orders, :index
|
||||
live "/orders/:order_number", Shop.OrderDetail, :show
|
||||
|
||||
# Catch-all for custom CMS pages — must be last
|
||||
live "/:slug", Shop.CustomPage, :show
|
||||
end
|
||||
|
||||
# Checkout (POST — creates Stripe session and redirects)
|
||||
post "/checkout", CheckoutController, :create
|
||||
|
||||
# Order lookup (no-JS fallback for contact page form)
|
||||
post "/contact/lookup", OrderLookupController, :lookup
|
||||
|
||||
# Cart form actions (no-JS fallbacks for LiveView cart events)
|
||||
post "/cart/add", CartController, :add
|
||||
post "/cart/remove", CartController, :remove
|
||||
post "/cart/update", CartController, :update_item
|
||||
post "/cart/country", CartController, :update_country
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user