From 39e02f0d9b6ee1453f3afdcf89f2f5df8a89f34b Mon Sep 17 00:00:00 2001
From: Samir Boulahtit
Date: Sun, 19 Apr 2026 22:20:52 +0200
Subject: [PATCH] fix(loyalty): terminal icons, server-side i18n, category in
transactions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Fix icons: plus-circle → plus, backspace → arrow-left
- Convert terminal $t() calls to server-side _() for card_label,
stamps_until_reward, reward_label, not_enough_stamps
- Inject transaction type labels as server-rendered window._txLabels
object (eliminates all async i18n warnings on terminal page)
- Resolve category_names in store transactions list endpoint
Co-Authored-By: Claude Opus 4.6 (1M context)
---
app/modules/loyalty/routes/api/store.py | 11 ++++++++
.../static/store/js/loyalty-terminal.js | 6 ++--
.../templates/loyalty/store/terminal.html | 28 +++++++++++++++----
3 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/app/modules/loyalty/routes/api/store.py b/app/modules/loyalty/routes/api/store.py
index f11c8fd9..aadced4c 100644
--- a/app/modules/loyalty/routes/api/store.py
+++ b/app/modules/loyalty/routes/api/store.py
@@ -652,11 +652,22 @@ def list_store_transactions(
db, merchant_id, skip=skip, limit=limit
)
+ from app.modules.loyalty.services.category_service import category_service
+
tx_responses = []
for t in transactions:
tx = TransactionResponse.model_validate(t)
if t.card and t.card.customer:
tx.customer_name = t.card.customer.full_name
+ if t.category_ids and isinstance(t.category_ids, list):
+ names = []
+ for cid in t.category_ids:
+ name = category_service.validate_category_for_store(
+ db, cid, t.store_id or 0
+ )
+ if name:
+ names.append(name)
+ tx.category_names = names if names else None
tx_responses.append(tx)
return TransactionListResponse(transactions=tx_responses, total=total)
diff --git a/app/modules/loyalty/static/store/js/loyalty-terminal.js b/app/modules/loyalty/static/store/js/loyalty-terminal.js
index 64adf977..688e0f7e 100644
--- a/app/modules/loyalty/static/store/js/loyalty-terminal.js
+++ b/app/modules/loyalty/static/store/js/loyalty-terminal.js
@@ -369,9 +369,11 @@ function storeLoyaltyTerminal() {
getTransactionLabel(tx) {
const type = tx.transaction_type;
if (type) {
- return I18n.t('loyalty.transactions.' + type, {defaultValue: type.replace(/_/g, ' ')});
+ // Use server-rendered labels (no async flicker)
+ if (window._txLabels && window._txLabels[type]) return window._txLabels[type];
+ return type.replace(/_/g, ' ');
}
- return I18n.t('loyalty.common.unknown');
+ return 'Unknown';
},
getTransactionColor(tx) {
diff --git a/app/modules/loyalty/templates/loyalty/store/terminal.html b/app/modules/loyalty/templates/loyalty/store/terminal.html
index 4f3f1e2a..87502e80 100644
--- a/app/modules/loyalty/templates/loyalty/store/terminal.html
+++ b/app/modules/loyalty/templates/loyalty/store/terminal.html
@@ -129,7 +129,7 @@
+ x-text="selectedCard?.stamps_until_reward > 0 ? '{{ _('loyalty.store.terminal.more_for_reward') }}'.replace('{count}', selectedCard.stamps_until_reward) : '{{ _('loyalty.store.terminal.ready_to_redeem') }}'">
@@ -168,7 +168,7 @@
-
+
{{ _('loyalty.store.terminal.add_stamp') }}
@@ -192,7 +192,7 @@
{{ _('loyalty.store.terminal.redeem_stamps') }}
+ x-text="selectedCard?.can_redeem_stamps ? '{{ _('loyalty.store.terminal.reward_label') }}' + ': ' + (selectedCard?.stamp_reward_description || program?.stamps_reward_description || '{{ _('loyalty.store.terminal.free_item') }}') : '{{ _('loyalty.store.terminal.not_enough_stamps') }}'">