fix(loyalty): drop unregistered device-tablet icon, guard QR template against null
Some checks failed
CI / ruff (push) Successful in 14s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has been cancelled

- The icon registry has no 'device-tablet' (closest available is 'phone',
  which is already used for similar device-mobile contexts). Replace
  uses I added in the merchant menu item and the empty state.

- The pairing-QR modal uses x-show on the QR/payload blocks, but x-show
  only toggles display while Alpine still evaluates child expressions.
  pairingResult is null on first render, so the template threw "can't
  access property 'qr_png_base64'/'setup_payload', pairingResult is
  null" until pairing actually fired. Wrap the block in
  <template x-if="pairingResult"> so the bindings only mount when the
  data exists.

(There is a third 'device-tablet' reference in store/analytics.html
that predates this work — leaving it for a separate cleanup since
it's not on the Android-rollout path.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 21:31:12 +02:00
parent cb8e6a0ec3
commit 90b5b3d135
2 changed files with 13 additions and 9 deletions

View File

@@ -282,7 +282,7 @@ loyalty_module = ModuleDefinition(
MenuItemDefinition(
id="devices",
label_key="loyalty.menu.terminal_devices",
icon="device-tablet",
icon="phone",
route="/merchants/loyalty/devices",
order=32,
),

View File

@@ -55,7 +55,7 @@
<tr>
<td :colspan="'{{ '6' if show_store_filter else '5' }}'" class="px-4 py-8 text-center text-gray-600 dark:text-gray-400">
<div class="flex flex-col items-center">
<span x-html="$icon('device-tablet', 'w-12 h-12 mb-2 text-gray-300')"></span>
<span x-html="$icon('phone', 'w-12 h-12 mb-2 text-gray-300')"></span>
<p class="font-medium">{{ _('loyalty.terminal_devices.no_devices') }}</p>
</div>
</td>
@@ -150,13 +150,17 @@
{{ _('loyalty.terminal_devices.qr_warning_body') }}
</p>
</div>
<div class="flex items-center justify-center bg-white p-4 rounded-lg" x-show="pairingResult">
<img :src="pairingResult.qr_png_base64" alt="Pairing QR code" class="w-64 h-64">
</div>
<details class="text-sm" x-show="pairingResult">
<summary class="cursor-pointer text-gray-600 dark:text-gray-400">{{ _('loyalty.terminal_devices.show_payload') }}</summary>
<pre class="mt-2 p-3 text-xs bg-gray-50 dark:bg-gray-900 rounded overflow-x-auto" x-text="JSON.stringify(pairingResult.setup_payload, null, 2)"></pre>
</details>
<template x-if="pairingResult">
<div>
<div class="flex items-center justify-center bg-white p-4 rounded-lg">
<img :src="pairingResult.qr_png_base64" alt="Pairing QR code" class="w-64 h-64">
</div>
<details class="text-sm mt-3">
<summary class="cursor-pointer text-gray-600 dark:text-gray-400">{{ _('loyalty.terminal_devices.show_payload') }}</summary>
<pre class="mt-2 p-3 text-xs bg-gray-50 dark:bg-gray-900 rounded overflow-x-auto" x-text="JSON.stringify(pairingResult.setup_payload, null, 2)"></pre>
</details>
</div>
</template>
<div class="flex items-center justify-end">
<button @click="closeQrModal()" type="button"
class="px-4 py-2 text-sm font-medium text-white bg-purple-600 rounded-lg hover:bg-purple-700">