refactor: rename shopLayoutData to storefrontLayoutData
Some checks failed
CI / ruff (push) Successful in 11s
CI / pytest (push) Failing after 46m49s
CI / validate (push) Successful in 23s
CI / dependency-scanning (push) Successful in 30s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped

Align Alpine.js base component naming with storefront terminology.
Updated across all storefront JS, templates, and documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 19:06:45 +01:00
parent ec888f2e94
commit a6e6d9be8e
25 changed files with 130 additions and 130 deletions

View File

@@ -175,7 +175,7 @@
<script> <script>
document.addEventListener('alpine:init', () => { document.addEventListener('alpine:init', () => {
Alpine.data('shoppingCart', () => { Alpine.data('shoppingCart', () => {
const baseData = shopLayoutData(); const baseData = storefrontLayoutData();
return { return {
...baseData, ...baseData,

View File

@@ -146,7 +146,7 @@ window.CATEGORY_SLUG = '{{ category_slug | default("") }}';
document.addEventListener('alpine:init', () => { document.addEventListener('alpine:init', () => {
Alpine.data('shopCategory', () => ({ Alpine.data('shopCategory', () => ({
...shopLayoutData(), ...storefrontLayoutData(),
// Data // Data
categorySlug: window.CATEGORY_SLUG, categorySlug: window.CATEGORY_SLUG,

View File

@@ -218,7 +218,7 @@ window.STORE_ID = {{ store.id }};
document.addEventListener('alpine:init', () => { document.addEventListener('alpine:init', () => {
Alpine.data('productDetail', () => { Alpine.data('productDetail', () => {
const baseData = shopLayoutData(); const baseData = storefrontLayoutData();
return { return {
...baseData, ...baseData,

View File

@@ -145,7 +145,7 @@
<script> <script>
document.addEventListener('alpine:init', () => { document.addEventListener('alpine:init', () => {
Alpine.data('shopProducts', () => ({ Alpine.data('shopProducts', () => ({
...shopLayoutData(), ...storefrontLayoutData(),
products: [], products: [],
loading: true, loading: true,
filters: { filters: {
@@ -205,7 +205,7 @@ document.addEventListener('alpine:init', () => {
this.loadProducts(); this.loadProducts();
}, },
// formatPrice is inherited from shopLayoutData() via spread operator // formatPrice is inherited from storefrontLayoutData() via spread operator
async addToCart(product) { async addToCart(product) {
console.log('[SHOP] Adding to cart:', product); console.log('[SHOP] Adding to cart:', product);

View File

@@ -170,7 +170,7 @@
<script> <script>
document.addEventListener('alpine:init', () => { document.addEventListener('alpine:init', () => {
Alpine.data('shopSearch', () => ({ Alpine.data('shopSearch', () => ({
...shopLayoutData(), ...storefrontLayoutData(),
// Search state // Search state
searchInput: '', searchInput: '',

View File

@@ -135,7 +135,7 @@
<script> <script>
document.addEventListener('alpine:init', () => { document.addEventListener('alpine:init', () => {
Alpine.data('shopWishlist', () => ({ Alpine.data('shopWishlist', () => ({
...shopLayoutData(), ...storefrontLayoutData(),
// Data // Data
items: [], items: [],

View File

@@ -477,7 +477,7 @@
<script> <script>
function checkoutPage() { function checkoutPage() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
// State // State
loading: true, loading: true,
@@ -595,8 +595,8 @@ function checkoutPage() {
console.log('[CHECKOUT] Initializing...'); console.log('[CHECKOUT] Initializing...');
// Initialize session // Initialize session
if (typeof shopLayoutData === 'function') { if (typeof storefrontLayoutData === 'function') {
const baseData = shopLayoutData(); const baseData = storefrontLayoutData();
if (baseData.init) { if (baseData.init) {
baseData.init.call(this); baseData.init.call(this);
} }

View File

@@ -7,7 +7,7 @@
{% block meta_description %}{{ page.meta_description or store.description or store.name }}{% endblock %} {% block meta_description %}{{ page.meta_description or store.description or store.name }}{% endblock %}
{# Alpine.js component #} {# Alpine.js component #}
{% block alpine_data %}shopLayoutData(){% endblock %} {% block alpine_data %}storefrontLayoutData(){% endblock %}
{% block content %} {% block content %}
<div class="min-h-screen"> <div class="min-h-screen">

View File

@@ -7,7 +7,7 @@
{% block meta_description %}{{ page.meta_description or store.description or store.name }}{% endblock %} {% block meta_description %}{{ page.meta_description or store.description or store.name }}{% endblock %}
{# Alpine.js component #} {# Alpine.js component #}
{% block alpine_data %}shopLayoutData(){% endblock %} {% block alpine_data %}storefrontLayoutData(){% endblock %}
{% block content %} {% block content %}
<div class="min-h-screen"> <div class="min-h-screen">

View File

@@ -16,7 +16,7 @@ const shopLog = {
* Shop Layout Data * Shop Layout Data
* Base Alpine.js component for shop pages * Base Alpine.js component for shop pages
*/ */
function shopLayoutData() { function storefrontLayoutData() {
return { return {
// Theme state // Theme state
dark: localStorage.getItem('shop-theme') === 'dark', dark: localStorage.getItem('shop-theme') === 'dark',
@@ -243,7 +243,7 @@ function shopLayoutData() {
} }
// Make available globally // Make available globally
window.shopLayoutData = shopLayoutData; window.storefrontLayoutData = storefrontLayoutData;
/** /**
* Language Selector Component * Language Selector Component

View File

@@ -318,7 +318,7 @@
<script> <script>
function addressesPage() { function addressesPage() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
// State // State
loading: true, loading: true,

View File

@@ -163,7 +163,7 @@
<script> <script>
function accountDashboard() { function accountDashboard() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
showLogoutModal: false, showLogoutModal: false,
confirmLogout() { confirmLogout() {

View File

@@ -288,7 +288,7 @@
<script> <script>
function shopProfilePage() { function shopProfilePage() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
// State // State
profile: null, profile: null,
@@ -508,7 +508,7 @@ function shopProfilePage() {
} }
}, },
// formatPrice is inherited from shopLayoutData() via spread operator // formatPrice is inherited from storefrontLayoutData() via spread operator
formatDate(dateStr) { formatDate(dateStr) {
if (!dateStr) return '-'; if (!dateStr) return '-';

View File

@@ -3,7 +3,7 @@
function customerLoyaltyDashboard() { function customerLoyaltyDashboard() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
// Data // Data
card: null, card: null,

View File

@@ -3,7 +3,7 @@
function customerLoyaltyEnroll() { function customerLoyaltyEnroll() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
// Program info // Program info
program: null, program: null,

View File

@@ -3,7 +3,7 @@
function customerLoyaltyHistory() { function customerLoyaltyHistory() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
// Data // Data
card: null, card: null,

View File

@@ -86,7 +86,7 @@
<script> <script>
function customerLoyaltyEnrollSuccess() { function customerLoyaltyEnrollSuccess() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
walletUrls: { google_wallet_url: null, apple_wallet_url: null }, walletUrls: { google_wallet_url: null, apple_wallet_url: null },
async init() { async init() {
try { try {

View File

@@ -253,7 +253,7 @@
<script> <script>
function shopMessages() { function shopMessages() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
loading: true, loading: true,
conversations: [], conversations: [],
selectedConversation: null, selectedConversation: null,

View File

@@ -340,7 +340,7 @@
<script> <script>
function shopOrderDetailPage() { function shopOrderDetailPage() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
// State // State
order: null, order: null,
@@ -416,7 +416,7 @@ function shopOrderDetailPage() {
return this.statuses[status]?.class || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200'; return this.statuses[status]?.class || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200';
}, },
// formatPrice is inherited from shopLayoutData() via spread operator // formatPrice is inherited from storefrontLayoutData() via spread operator
formatDateTime(dateStr) { formatDateTime(dateStr) {
if (!dateStr) return '-'; if (!dateStr) return '-';

View File

@@ -134,7 +134,7 @@
<script> <script>
function shopOrdersPage() { function shopOrdersPage() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
// State // State
orders: [], orders: [],
@@ -209,7 +209,7 @@ function shopOrdersPage() {
return this.statuses[status]?.class || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200'; return this.statuses[status]?.class || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200';
}, },
// formatPrice is inherited from shopLayoutData() via spread operator // formatPrice is inherited from storefrontLayoutData() via spread operator
formatDate(dateStr) { formatDate(dateStr) {
if (!dateStr) return '-'; if (!dateStr) return '-';

View File

@@ -1,7 +1,7 @@
{# app/templates/storefront/base.html #} {# app/templates/storefront/base.html #}
{# Base template for store shop frontend with theme support #} {# Base template for store shop frontend with theme support #}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" x-data="{% block alpine_data %}shopLayoutData(){% endblock %}" x-bind:class="{ 'dark': dark }"> <html lang="en" x-data="{% block alpine_data %}storefrontLayoutData(){% endblock %}" x-bind:class="{ 'dark': dark }">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">

View File

@@ -412,7 +412,7 @@ All authentication pages follow the shop template pattern:
<script> <script>
function componentName() { function componentName() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
// Component-specific data/methods // Component-specific data/methods
} }
} }
@@ -487,7 +487,7 @@ Custom Tailwind CSS modal for logout confirmation instead of browser's native `c
```javascript ```javascript
function accountDashboard() { function accountDashboard() {
return { return {
...shopLayoutData(), ...storefrontLayoutData(),
showLogoutModal: false, // Modal state showLogoutModal: false, // Modal state
confirmLogout() { confirmLogout() {

View File

@@ -291,7 +291,7 @@ Scripts MUST load in this exact order (see base.html):
7. Page-specific JS ← Optional page scripts 7. Page-specific JS ← Optional page scripts
Why This Order Matters: Why This Order Matters:
• shop-layout.js defines shopLayoutData() BEFORE Alpine initializes • shop-layout.js defines storefrontLayoutData() BEFORE Alpine initializes
• Alpine.js defers to ensure DOM is ready • Alpine.js defers to ensure DOM is ready
• Shared utilities available to all scripts • Shared utilities available to all scripts
• Icons and logging available immediately • Icons and logging available immediately
@@ -311,7 +311,7 @@ Alpine.js Component Architecture:
Provides shared functionality for all shop pages: Provides shared functionality for all shop pages:
function shopLayoutData() { function storefrontLayoutData() {
return { return {
// Theme state // Theme state
dark: localStorage.getItem('shop-theme') === 'dark', dark: localStorage.getItem('shop-theme') === 'dark',
@@ -368,16 +368,16 @@ Provides shared functionality for all shop pages:
} }
// Make globally available // Make globally available
window.shopLayoutData = shopLayoutData; window.storefrontLayoutData = storefrontLayoutData;
⭐ PAGE-SPECIFIC COMPONENTS: ⭐ PAGE-SPECIFIC COMPONENTS:
Each page extends shopLayoutData() for page-specific functionality: Each page extends storefrontLayoutData() for page-specific functionality:
// Example: products.html // Example: products.html
document.addEventListener('alpine:init', () => { document.addEventListener('alpine:init', () => {
Alpine.data('shopProducts', () => ({ Alpine.data('shopProducts', () => ({
...shopLayoutData(), // Extend base component ...storefrontLayoutData(), // Extend base component
// Page-specific state // Page-specific state
products: [], products: [],
@@ -387,7 +387,7 @@ Each page extends shopLayoutData() for page-specific functionality:
// Override init to add page-specific initialization // Override init to add page-specific initialization
async init() { async init() {
shopLog.info('Products page initializing...'); shopLog.info('Products page initializing...');
this.loadCart(); // From shopLayoutData this.loadCart(); // From storefrontLayoutData
await this.loadProducts(); // Page-specific await this.loadProducts(); // Page-specific
}, },
@@ -405,18 +405,18 @@ Template Usage:
────────────────────────────────────────────────────────────────── ──────────────────────────────────────────────────────────────────
{# In base.html - uses block to allow override #} {# In base.html - uses block to allow override #}
<html x-data="{% block alpine_data %}shopLayoutData(){% endblock %}" <html x-data="{% block alpine_data %}storefrontLayoutData(){% endblock %}"
x-bind:class="{ 'dark': dark }"> x-bind:class="{ 'dark': dark }">
{# In products.html - overrides to use page-specific component #} {# In products.html - overrides to use page-specific component #}
{% block alpine_data %}shopProducts(){% endblock %} {% block alpine_data %}shopProducts(){% endblock %}
{# In home.html - uses default base component #} {# In home.html - uses default base component #}
{# No block override needed, inherits shopLayoutData() #} {# No block override needed, inherits storefrontLayoutData() #}
⭐ COMPONENT HIERARCHY: ⭐ COMPONENT HIERARCHY:
shopLayoutData() ← Base component (shared state & methods) storefrontLayoutData() ← Base component (shared state & methods)
shopProducts() ← Products page (extends base + products state) shopProducts() ← Products page (extends base + products state)
shopCart() ← Cart page (extends base + cart state) shopCart() ← Cart page (extends base + cart state)
@@ -435,11 +435,11 @@ Tradeoffs:
⚠️ Can't easily split page into independent sub-components ⚠️ Can't easily split page into independent sub-components
Best Practices: Best Practices:
1. Always extend shopLayoutData() in page components 1. Always extend storefrontLayoutData() in page components
2. Override init() if you need page-specific initialization 2. Override init() if you need page-specific initialization
3. Call parent methods when needed (this.loadCart(), this.showToast()) 3. Call parent methods when needed (this.loadCart(), this.showToast())
4. Keep page-specific state in the page component 4. Keep page-specific state in the page component
5. Keep shared state in shopLayoutData() 5. Keep shared state in storefrontLayoutData()
Responsibilities: Responsibilities:
✅ Load products from API ✅ Load products from API

View File

@@ -445,7 +445,7 @@ function shop[PageName]() {
pageLog.info('Adding to cart:', item.name); pageLog.info('Adding to cart:', item.name);
// Get cart from shop layout // Get cart from shop layout
const shopLayout = Alpine.store('shop') || window.shopLayoutData(); const shopLayout = Alpine.store('shop') || window.storefrontLayoutData();
if (shopLayout && typeof shopLayout.addToCart === 'function') { if (shopLayout && typeof shopLayout.addToCart === 'function') {
shopLayout.addToCart(item, quantity); shopLayout.addToCart(item, quantity);
@@ -463,7 +463,7 @@ function shop[PageName]() {
* Show toast notification * Show toast notification
*/ */
showToast(message, type = 'info') { showToast(message, type = 'info') {
const shopLayout = Alpine.store('shop') || window.shopLayoutData(); const shopLayout = Alpine.store('shop') || window.storefrontLayoutData();
if (shopLayout && typeof shopLayout.showToast === 'function') { if (shopLayout && typeof shopLayout.showToast === 'function') {
shopLayout.showToast(message, type); shopLayout.showToast(message, type);
} }
@@ -606,7 +606,7 @@ async loadProduct(id) {
} }
addToCartWithQuantity() { addToCartWithQuantity() {
const shopLayout = window.shopLayoutData(); const shopLayout = window.storefrontLayoutData();
shopLayout.addToCart(this.product, this.quantity); shopLayout.addToCart(this.product, this.quantity);
} }
``` ```
@@ -663,19 +663,19 @@ async init() {
} }
loadCart() { loadCart() {
const shopLayout = window.shopLayoutData(); const shopLayout = window.storefrontLayoutData();
this.cart = shopLayout.cart; this.cart = shopLayout.cart;
this.calculateTotals(); this.calculateTotals();
} }
updateQuantity(productId, quantity) { updateQuantity(productId, quantity) {
const shopLayout = window.shopLayoutData(); const shopLayout = window.storefrontLayoutData();
shopLayout.updateCartItem(productId, quantity); shopLayout.updateCartItem(productId, quantity);
this.loadCart(); this.loadCart();
} }
removeItem(productId) { removeItem(productId) {
const shopLayout = window.shopLayoutData(); const shopLayout = window.storefrontLayoutData();
shopLayout.removeFromCart(productId); shopLayout.removeFromCart(productId);
this.loadCart(); this.loadCart();
} }
@@ -754,7 +754,7 @@ Always use the shop layout's cart methods:
```javascript ```javascript
// ✅ GOOD: Uses shop layout // ✅ GOOD: Uses shop layout
const shopLayout = window.shopLayoutData(); const shopLayout = window.storefrontLayoutData();
shopLayout.addToCart(product, quantity); shopLayout.addToCart(product, quantity);
// ❌ BAD: Direct localStorage manipulation // ❌ BAD: Direct localStorage manipulation

View File

@@ -56,7 +56,7 @@ Session ID not properly initialized in Alpine.js components.
**How it Works:** **How it Works:**
- Cart uses session ID stored in localStorage as `cart_session_id` - Cart uses session ID stored in localStorage as `cart_session_id`
- `shopLayoutData()` base component initializes `sessionId` in its `init()` method - `storefrontLayoutData()` base component initializes `sessionId` in its `init()` method
- Child components (product, cart) must call parent `init()` to get `sessionId` - Child components (product, cart) must call parent `init()` to get `sessionId`
- If parent init isn't called, `sessionId` is `undefined` - If parent init isn't called, `sessionId` is `undefined`
@@ -295,7 +295,7 @@ Child component doesn't call parent `init()` method.
**Solution:** **Solution:**
```javascript ```javascript
// Store reference to parent // Store reference to parent
const baseData = shopLayoutData(); const baseData = storefrontLayoutData();
return { return {
...baseData, ...baseData,