The control card says which charger the buttons move

The product shot was already in the account's charger list and already
relayed; only the information card ever drew it. The card whose buttons
start a session had no sign at all of which charger it meant — the name
lives two cards further down, and two A5191s on one account look alike in
a dropdown.

Identified by the serial in force rather than by the record highlighted
in the list beside it. They are usually the same charger, and when they
are not, a picture of the other one is worse than no picture. Either
source will do: the account's own list, or the live half held per
provider, which carry the same image.

A shot that will not load is remembered by its URL, so the picture stops
being drawn and comes back on its own if the service starts answering for
it again — nothing to reset when the serial changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tajniak81
2026-09-03 18:20:33 +02:00
co-authored by Claude Opus 5
parent 9d4aecb668
commit 3fddab6815
+45
View File
@@ -1000,6 +1000,31 @@ function liveFor(c) {
return chargerLive.value[c.providerChargerId] || chargerLive.value[c.serial] || null;
}
// --- The charger the buttons act on, as a picture and a name ------------------
//
// The control card drives whichever serial is in force, which is not always the
// record highlighted in the list beside it, so it identifies its charger by that
// serial rather than by the selection. Two sources carry the same product shot:
// the account's own charger list, and the live half held per provider. Either
// will do; the account's is the one that arrives without the home tab having
// been opened.
//
// It lives here rather than up with the other ctl* values because both of its
// sources do, and a lookup reads better next to the map it reads from.
function accountCharger(sn) {
if (!sn) return null;
return chargers.value.find((c) => c.sn === sn) || chargerLive.value[sn] || null;
}
const ctlImageUrl = computed(() => accountCharger(ctlSerial.value.trim())?.imageUrl || "");
const ctlChargerName = computed(() => accountCharger(ctlSerial.value.trim())?.name || "");
// A product shot is a URL from the service, and a URL can 404. Remembered per
// URL rather than per charger, so the picture simply stops being drawn and comes
// back on its own if the service starts answering for it again — no reset to
// forget when the serial changes.
const imageFailed = ref({});
// How the charger is registered on the account, in the service's own terms.
function sourcesLabel(sources) {
if (!sources?.length) return "";
@@ -1929,6 +1954,26 @@ onMounted(async () => {
<div v-show="isOpen('control')">
<!-- Which charger these buttons act on. The card said nothing about
that before: the name is two cards further down, and the picture
is the fastest way to tell two chargers on one account apart. -->
<div
v-if="ctlImageUrl || ctlChargerName"
class="mt-3 flex items-center gap-3 rounded-control bg-sunken p-3"
>
<img
v-if="ctlImageUrl && !imageFailed[ctlImageUrl]"
:src="ctlImageUrl"
alt=""
class="h-16 w-16 shrink-0 rounded object-contain"
@error="imageFailed[ctlImageUrl] = true"
/>
<div class="min-w-0">
<p v-if="ctlChargerName" class="truncate text-sm font-semibold text-strong">{{ ctlChargerName }}</p>
<p class="data truncate text-[11px] text-muted">{{ ctlSerial }}</p>
</div>
</div>
<div class="mt-3 grid grid-cols-2 gap-2">
<div class="rounded-control bg-sunken px-3 py-2">
<div class="data text-sm font-semibold text-strong">{{ ctlStatusLabel }}</div>