fix(loyalty): align menu item IDs with URL segments for sidebar highlight

The store and merchant init-alpine.js derive currentPage from the URL's
last segment (e.g., /loyalty/program -> 'program'). Loyalty menu items
used prefixed IDs like 'loyalty-program' which never matched, so sidebar
items never highlighted.

Fixed by renaming all store/merchant menu item IDs and JS currentPage
values to match URL segments: program, cards, analytics, transactions,
pins, settings — consistent with how every other module works.

Also reverted the init-alpine.js guard that broke storeCode extraction,
and added missing loyalty.common.contact_admin_setup translation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-23 18:32:50 +01:00
parent ce0caa5685
commit 1d90bfe044
20 changed files with 3497 additions and 3494 deletions

View File

@@ -65,16 +65,14 @@ function data() {
openSections: getStoreSidebarSectionsFromStorage(), openSections: getStoreSidebarSectionsFromStorage(),
init() { init() {
// Set current page from URL (only if not already set by child component) // Set current page from URL
if (!this.currentPage) { const path = window.location.pathname;
const path = window.location.pathname; const segments = path.split('/').filter(Boolean);
const segments = path.split('/').filter(Boolean); // For /store/ABC/orders/123 -> 'orders' (skip numeric IDs)
// For /store/ABC/orders/123 -> 'orders' (skip numeric IDs) const last = segments[segments.length - 1] || 'dashboard';
const last = segments[segments.length - 1] || 'dashboard'; this.currentPage = /^\d+$/.test(last) && segments.length > 2
this.currentPage = /^\d+$/.test(last) && segments.length > 2 ? segments[segments.length - 2]
? segments[segments.length - 2] : last;
: last;
}
// Get store code from server-rendered value or URL fallback // Get store code from server-rendered value or URL fallback
this.storeCode = window.STORE_CODE || null; this.storeCode = window.STORE_CODE || null;

View File

@@ -132,16 +132,17 @@ loyalty_module = ModuleDefinition(
FrontendType.STORE: [ FrontendType.STORE: [
"terminal", # Loyalty terminal "terminal", # Loyalty terminal
"cards", # Customer cards "cards", # Customer cards
"loyalty-program", # Program config "pins", # Staff PINs
"loyalty-analytics", # Store analytics "program", # Program config
"analytics", # Store analytics
], ],
FrontendType.MERCHANT: [ FrontendType.MERCHANT: [
"loyalty-program", # Merchant loyalty program "program", # Merchant loyalty program
"loyalty-cards", # Customer cards "cards", # Customer cards
"loyalty-analytics", # Merchant loyalty analytics "analytics", # Merchant loyalty analytics
"loyalty-transactions", # Transaction feed "transactions", # Transaction feed
"loyalty-pins", # Staff PINs "pins", # Staff PINs
"loyalty-settings", # Settings (read-only) "settings", # Settings (read-only)
], ],
}, },
# New module-driven menu definitions # New module-driven menu definitions
@@ -210,7 +211,7 @@ loyalty_module = ModuleDefinition(
requires_permission="loyalty.view_programs", requires_permission="loyalty.view_programs",
), ),
MenuItemDefinition( MenuItemDefinition(
id="loyalty-program", id="program",
label_key="loyalty.menu.program", label_key="loyalty.menu.program",
icon="cog", icon="cog",
route="/store/{store_code}/loyalty/program", route="/store/{store_code}/loyalty/program",
@@ -218,7 +219,7 @@ loyalty_module = ModuleDefinition(
requires_permission="loyalty.view_programs", requires_permission="loyalty.view_programs",
), ),
MenuItemDefinition( MenuItemDefinition(
id="loyalty-analytics", id="analytics",
label_key="loyalty.menu.analytics", label_key="loyalty.menu.analytics",
icon="chart-bar", icon="chart-bar",
route="/store/{store_code}/loyalty/analytics", route="/store/{store_code}/loyalty/analytics",
@@ -236,42 +237,42 @@ loyalty_module = ModuleDefinition(
order=60, order=60,
items=[ items=[
MenuItemDefinition( MenuItemDefinition(
id="loyalty-program", id="program",
label_key="loyalty.menu.program", label_key="loyalty.menu.program",
icon="gift", icon="gift",
route="/merchants/loyalty/program", route="/merchants/loyalty/program",
order=10, order=10,
), ),
MenuItemDefinition( MenuItemDefinition(
id="loyalty-cards", id="cards",
label_key="loyalty.menu.customer_cards", label_key="loyalty.menu.customer_cards",
icon="identification", icon="identification",
route="/merchants/loyalty/cards", route="/merchants/loyalty/cards",
order=15, order=15,
), ),
MenuItemDefinition( MenuItemDefinition(
id="loyalty-analytics", id="analytics",
label_key="loyalty.menu.analytics", label_key="loyalty.menu.analytics",
icon="chart-bar", icon="chart-bar",
route="/merchants/loyalty/analytics", route="/merchants/loyalty/analytics",
order=20, order=20,
), ),
MenuItemDefinition( MenuItemDefinition(
id="loyalty-transactions", id="transactions",
label_key="loyalty.menu.transactions", label_key="loyalty.menu.transactions",
icon="clock", icon="clock",
route="/merchants/loyalty/transactions", route="/merchants/loyalty/transactions",
order=25, order=25,
), ),
MenuItemDefinition( MenuItemDefinition(
id="loyalty-pins", id="pins",
label_key="loyalty.menu.staff_pins", label_key="loyalty.menu.staff_pins",
icon="key", icon="key",
route="/merchants/loyalty/pins", route="/merchants/loyalty/pins",
order=30, order=30,
), ),
MenuItemDefinition( MenuItemDefinition(
id="loyalty-settings", id="settings",
label_key="loyalty.menu.settings", label_key="loyalty.menu.settings",
icon="cog", icon="cog",
route="/merchants/loyalty/settings", route="/merchants/loyalty/settings",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ const loyaltyAnalyticsLog = window.LogConfig.loggers.loyaltyAnalytics || window.
function merchantLoyaltyAnalytics() { function merchantLoyaltyAnalytics() {
return { return {
...data(), ...data(),
currentPage: 'loyalty-analytics', currentPage: 'analytics',
program: null, program: null,
locations: [], locations: [],

View File

@@ -7,7 +7,7 @@ function merchantLoyaltyCardDetail() {
return loyaltyCardDetailView({ return loyaltyCardDetailView({
apiPrefix: '/merchants/loyalty', apiPrefix: '/merchants/loyalty',
backUrl: '/merchants/loyalty/cards', backUrl: '/merchants/loyalty/cards',
currentPage: 'loyalty-cards', currentPage: 'cards',
}); });
} }

View File

@@ -8,7 +8,7 @@ function merchantLoyaltyCards() {
apiPrefix: '/merchants/loyalty', apiPrefix: '/merchants/loyalty',
baseUrl: '/merchants/loyalty/cards', baseUrl: '/merchants/loyalty/cards',
showStoreFilter: true, showStoreFilter: true,
currentPage: 'loyalty-cards', currentPage: 'cards',
}); });
} }

View File

@@ -6,7 +6,7 @@ const merchantSettingsViewLog = window.LogConfig.loggers.merchantSettingsView ||
function merchantLoyaltyMerchantSettings() { function merchantLoyaltyMerchantSettings() {
return { return {
...data(), ...data(),
currentPage: 'loyalty-settings', currentPage: 'settings',
settings: null, settings: null,
loading: false, loading: false,

View File

@@ -8,7 +8,7 @@ function merchantLoyaltyPins() {
apiPrefix: '/merchants/loyalty', apiPrefix: '/merchants/loyalty',
showStoreFilter: true, showStoreFilter: true,
showCrud: true, showCrud: true,
currentPage: 'loyalty-pins', currentPage: 'pins',
}); });
} }

View File

@@ -7,7 +7,7 @@ function merchantLoyaltySettings() {
return { return {
...data(), ...data(),
...createProgramFormMixin(), ...createProgramFormMixin(),
currentPage: 'loyalty-program', currentPage: 'program',
loading: false, loading: false,
error: null, error: null,

View File

@@ -7,7 +7,7 @@ function merchantLoyaltyTransactions() {
return loyaltyTransactionsList({ return loyaltyTransactionsList({
apiPrefix: '/merchants/loyalty', apiPrefix: '/merchants/loyalty',
showStoreFilter: true, showStoreFilter: true,
currentPage: 'loyalty-transactions', currentPage: 'transactions',
}); });
} }

View File

@@ -6,7 +6,7 @@ const loyaltyAnalyticsLog = window.LogConfig.loggers.loyaltyAnalytics || window.
function storeLoyaltyAnalytics() { function storeLoyaltyAnalytics() {
return { return {
...data(), ...data(),
currentPage: 'loyalty-analytics', currentPage: 'analytics',
program: null, program: null,

View File

@@ -6,7 +6,7 @@ const loyaltyCardDetailLog = window.LogConfig.loggers.loyaltyCardDetail || windo
function storeLoyaltyCardDetail() { function storeLoyaltyCardDetail() {
return { return {
...data(), ...data(),
currentPage: 'loyalty-card-detail', currentPage: 'cards',
cardId: null, cardId: null,
card: null, card: null,

View File

@@ -6,7 +6,7 @@ const loyaltyCardsLog = window.LogConfig.loggers.loyaltyCards || window.LogConfi
function storeLoyaltyCards() { function storeLoyaltyCards() {
return { return {
...data(), ...data(),
currentPage: 'loyalty-cards', currentPage: 'cards',
// Data // Data
cards: [], cards: [],

View File

@@ -6,7 +6,7 @@ const loyaltyEnrollLog = window.LogConfig.loggers.loyaltyEnroll || window.LogCon
function storeLoyaltyEnroll() { function storeLoyaltyEnroll() {
return { return {
...data(), ...data(),
currentPage: 'loyalty-enroll', currentPage: 'terminal',
program: null, program: null,
form: { form: {

View File

@@ -13,7 +13,7 @@ function loyaltySettings() {
...createProgramFormMixin(), ...createProgramFormMixin(),
// Page identifier // Page identifier
currentPage: 'loyalty-program', currentPage: 'program',
// State // State
loading: false, loading: false,

View File

@@ -13,7 +13,7 @@ function storeLoyaltyTerminal() {
...data(), ...data(),
// Page identifier // Page identifier
currentPage: 'loyalty-terminal', currentPage: 'terminal',
// Program state // Program state
program: null, program: null,

View File

@@ -61,7 +61,7 @@
function storeLoyaltyProgram() { function storeLoyaltyProgram() {
return { return {
...data(), ...data(),
currentPage: 'loyalty-program', currentPage: 'program',
program: null, program: null,
loading: false, loading: false,