Add AnalyticsHook to the coming_soon live session — the shop layout
fires an analytics:screen JS event but the session had no handler,
crashing the page on connect.
Centre the logo image (display:block from CSS reset needs
margin-inline:auto). Add a subtle "Admin" link at the bottom using
flex flow rather than fixed/absolute positioning so it works in
iframes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
site_name and site_description are shop identity, not theme concerns.
They now live in the Settings table as first-class settings with their
own assigns (@site_name, @site_description) piped through hooks and
plugs. The setup wizard writes site_name on account creation, and the
theme editor reads/writes via Settings.put_setting. Removed the
"configure your shop" checklist item since currency/country aren't
built yet. Also adds shop name field to setup wizard step 1.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
URL-based offset pagination with ?page=N for bookmarkable pages.
Admin views use push_patch, shop collection uses navigate links.
Responsive on mobile with horizontal-scroll tables and stacking
pagination controls. Includes dev seed script for testing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire up the contact form with action/method/name attrs so it works
without JavaScript. Add ContactNotifier, ContactController, and a
noscript info banner in the shop root layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
All 14 pages now render through PageRenderer. Theme editor preview
unified from 10 preview_page clauses to one function + page-context
helpers. PageTemplates module and 10 .heex template files deleted.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stage 4 of the page builder: all shop pages now render via
PageRenderer instead of inline templates or PageTemplates.
- Collection: full filter bar moved to renderer (category pills,
sort dropdown, CollectionFilters hook, empty state)
- PDP: related_products and reviews loaded via block data loaders
instead of manual queries
- Cart: page definition loaded in mount, subtotal computed in render
- Search: page definition loaded in mount, handle_params unchanged
- Added Phoenix.VerifiedRoutes to PageRenderer for ~p sigil
- Net -55 lines (128 added, 183 removed)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Home, Content (about/delivery/privacy/terms), Contact, and ErrorHTML
now render through the generic PageRenderer instead of hardcoded
templates. Block wrapper divs enable CSS grid targeting. Featured
products block supports layout/card_variant/columns settings for
different page contexts. Contact page uses CSS grid on data-block-type
attributes for two-column layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Variant options (colour, size) are now URL params handled via
handle_params instead of phx-click events. Swatches and size buttons
render as patch links in shop mode, so changing variants works as
plain navigation without JS. Quantity is now a number input that
submits with the form. Unavailable variants render as disabled spans.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every key shop flow now works via plain HTML forms when JS is
unavailable. LiveView progressively enhances when JS connects.
- PDP: form wraps variant/qty/add-to-cart with action="/cart/add"
- Cart page: qty +/- and remove use form POST fallbacks
- Cart/search header icons are now links with phx-click enhancement
- Collection sort form has GET action + noscript submit button
- New /search page with form-based search for no-JS users
- CartController gains add/remove/update_item POST actions
- CartHook gains update_quantity_form and remove_item_form handlers
- Fix flaky analytics tests caused by event table pollution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces hardcoded PreviewData placeholders with generated content
derived from real shop state: connected providers (production lead
times), shipping countries (grouped by region), shop country
(jurisdiction language and governing law), and feature flags
(abandoned cart recovery section, newsletter, VAT clause).
Returns policy correctly cites Consumer Contracts Regulations Reg
28(1)(b) for POD exemption and Consumer Rights Act for defective goods.
Cart recovery section uses jurisdiction-specific wording: PECR Reg 22
for UK, GDPR Art 6(1)(f) for EU, generic otherwise.
About page unchanged — shop owner's story to tell.
26 new tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Magic link flow on contact page: customer enters email, gets a
time-limited signed link, clicks through to /orders showing all their
paid orders and full detail pages with thumbnails and product links.
- OrderLookupController generates/verifies Phoenix.Token signed links
- Contact LiveView handles lookup_orders + reset_tracking events
- Orders and OrderDetail LiveViews gated by session email
- Order detail shows thumbnails, links to products still available
- .themed-button gets base padding/font-weight so all usages are consistent
- order-summary-card sticky scoped to .cart-grid (was leaking to orders list)
- 27 new tests (1095 total)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Product pages: Product schema (name, description, image, price/currency,
availability) + BreadcrumbList (Home > Category > Product). Home page:
Organization schema (name, url). Uses Jason with html_safe escaping so
the JSON is safe to embed in <script> tags.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Canonical: all shop pages now assign og_url (reusing the existing og:url
assign), which the layout renders as <link rel="canonical">. Collection
pages strip the sort param so ?sort=price_asc doesn't create a duplicate
canonical.
robots.txt: dynamic controller disallows /admin/, /api/, /users/,
/webhooks/, /checkout/. Removed robots.txt from static_paths so it
goes through the router instead of Plug.Static.
sitemap.xml: auto-generated from all visible products + categories +
static pages, served as application/xml. 8 tests.
Also updates PROGRESS.md: marks tasks 55, 58, 59, 61, 62 as done.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Product pages get og:type=product, og:url, og:image (hero image), and
twitter:card=summary_large_image. All other shop pages get og:type=website
and twitter:card=summary. og:title and og:description mirror the existing
page title and meta description.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Product pages: first 155 chars of description, stripped of HTML, truncated on word boundary.
Collections: contextual description based on collection type.
Content pages (about, delivery, privacy, terms): from hero_description text.
Contact: static description.
Home falls through to site_description from settings (already in layout).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Event call sites (product_view, add_to_cart, checkout_start, purchase)
were only passing visitor_hash and pathname, leaving browser, OS, screen
size and country nil. Add AnalyticsHook.attrs/1 helper to extract common
analytics fields from socket assigns, and use it in all LiveView event
call sites. Checkout controller reads the same fields from the session.
Also fix plug analytics test to clear stale events before assertions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three-layer pipeline: Plug for all HTTP requests (no JS needed), LiveView
hook for SPA navigations, JS hook for screen width. ETS-backed buffer
batches writes to SQLite every 10s. Daily-rotating salt for visitor hashing.
Includes admin dashboard with date ranges, visitor trends, top pages,
sources, devices, and e-commerce conversion funnel. Oban cron for 12-month
data retention.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Coming soon page was unstyled after Tailwind removal — replaced
utility classes with proper component CSS. Also removed dead h-full
classes from shop_root layout, adding height: 100% to the shop reset.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>