fix: loyalty module end-to-end — merchant route, store menus, sidebar, API error handling
Some checks failed
Some checks failed
- Add merchant loyalty overview route and template (was 404)
- Fix store loyalty route paths to match menu URLs (/{store_code}/loyalty/...)
- Add loyalty rewards card to storefront account dashboard
- Fix merchant overview to resolve merchant via get_merchant_for_current_user_page
- Fix store login to use store's primary platform for JWT token (interim fix)
- Fix apiClient to attach status/errorCode to thrown errors (fixes error.status
checks in 12+ JS files — loyalty settings, terminal, email templates, etc.)
- Hide "Add Product" sidebar button when catalog module is not enabled
- Add proposal doc for proper platform detection in store login flow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
116
app/modules/loyalty/templates/loyalty/merchant/overview.html
Normal file
116
app/modules/loyalty/templates/loyalty/merchant/overview.html
Normal file
@@ -0,0 +1,116 @@
|
||||
{# app/modules/loyalty/templates/loyalty/merchant/overview.html #}
|
||||
{% extends "merchant/base.html" %}
|
||||
|
||||
{% block title %}Loyalty Overview{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div x-data="merchantLoyaltyOverview()">
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="mb-8 mt-6">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-gray-100">Loyalty Overview</h2>
|
||||
<p class="mt-1 text-gray-500 dark:text-gray-400">Loyalty program statistics across all your stores.</p>
|
||||
</div>
|
||||
|
||||
<!-- No Program State -->
|
||||
<template x-if="!stats.program_id && !loading">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-12 text-center">
|
||||
<span x-html="$icon('gift', 'w-12 h-12 mx-auto text-gray-400')"></span>
|
||||
<h3 class="mt-4 text-lg font-medium text-gray-900 dark:text-white">No Loyalty Program</h3>
|
||||
<p class="mt-2 text-gray-500 dark:text-gray-400">
|
||||
Your loyalty program hasn't been set up yet. Contact the platform administrator or set it up from your store dashboard.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<template x-if="stats.program_id || loading">
|
||||
<div>
|
||||
<div class="grid gap-6 mb-8 md:grid-cols-2 xl:grid-cols-4">
|
||||
<!-- Total Cards -->
|
||||
<div class="flex items-center p-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div class="p-3 mr-4 text-purple-500 bg-purple-100 rounded-full dark:text-purple-100 dark:bg-purple-500">
|
||||
<span x-html="$icon('identification', 'w-5 h-5')"></span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1 text-sm font-medium text-gray-600 dark:text-gray-400">Total Cards</p>
|
||||
<p class="text-lg font-semibold text-gray-700 dark:text-gray-200" x-text="stats.total_cards || 0"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Active Cards -->
|
||||
<div class="flex items-center p-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div class="p-3 mr-4 text-green-500 bg-green-100 rounded-full dark:text-green-100 dark:bg-green-500">
|
||||
<span x-html="$icon('check-circle', 'w-5 h-5')"></span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1 text-sm font-medium text-gray-600 dark:text-gray-400">Active Cards</p>
|
||||
<p class="text-lg font-semibold text-gray-700 dark:text-gray-200" x-text="stats.active_cards || 0"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Points Issued (30d) -->
|
||||
<div class="flex items-center p-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div class="p-3 mr-4 text-blue-500 bg-blue-100 rounded-full dark:text-blue-100 dark:bg-blue-500">
|
||||
<span x-html="$icon('arrow-trending-up', 'w-5 h-5')"></span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1 text-sm font-medium text-gray-600 dark:text-gray-400">Points Issued (30d)</p>
|
||||
<p class="text-lg font-semibold text-gray-700 dark:text-gray-200" x-text="(stats.points_issued_30d || 0).toLocaleString()"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transactions (30d) -->
|
||||
<div class="flex items-center p-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div class="p-3 mr-4 text-orange-500 bg-orange-100 rounded-full dark:text-orange-100 dark:bg-orange-500">
|
||||
<span x-html="$icon('receipt-percent', 'w-5 h-5')"></span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1 text-sm font-medium text-gray-600 dark:text-gray-400">Transactions (30d)</p>
|
||||
<p class="text-lg font-semibold text-gray-700 dark:text-gray-200" x-text="stats.transactions_30d || 0"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- All Time Stats -->
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100">All-Time Statistics</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<div>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Total Points Issued</p>
|
||||
<p class="text-xl font-bold text-gray-900 dark:text-white" x-text="(stats.total_points_issued || 0).toLocaleString()"></p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Total Points Redeemed</p>
|
||||
<p class="text-xl font-bold text-gray-900 dark:text-white" x-text="(stats.total_points_redeemed || 0).toLocaleString()"></p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Points Redeemed (30d)</p>
|
||||
<p class="text-xl font-bold text-gray-900 dark:text-white" x-text="(stats.points_redeemed_30d || 0).toLocaleString()"></p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Outstanding Liability</p>
|
||||
<p class="text-xl font-bold text-gray-900 dark:text-white"
|
||||
x-text="'€' + ((stats.estimated_liability_cents || 0) / 100).toFixed(2)"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script>
|
||||
function merchantLoyaltyOverview() {
|
||||
return {
|
||||
loading: false,
|
||||
stats: {{ loyalty_stats | tojson }},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user