style(qsl): paper and LoTW first, then alphabetical
The channel list had grown in the order channels were added, so finding one meant remembering when it arrived. Paper QSL and LoTW lead — they are the two that carry an ARRL award — and the rest sort by name. One ordering function feeds both the picker and the status table, so the two cannot drift apart; the three extras-backed channels (OpsLog card, HAMLOG.online, HamQTH) now sit in that same list instead of being appended by hand after it.
This commit is contained in:
@@ -80,6 +80,19 @@ const CONF_LABEL_KEYS: Record<string, string> = {
|
||||
QSL: 'qedit.confQslPaper',
|
||||
};
|
||||
|
||||
// Reading order for the channel list: the two that carry an ARRL award first —
|
||||
// paper QSL and LoTW — then everything else alphabetically, so a channel is
|
||||
// found by its name rather than by remembering the order it was added in.
|
||||
const CONF_FIRST: Record<string, number> = { QSL: 0, LOTW: 1 };
|
||||
function confOrder<T extends { key: string; label: string }>(rows: T[]): T[] {
|
||||
return rows.slice().sort((a, b) => {
|
||||
const ra = CONF_FIRST[a.key] ?? 2;
|
||||
const rb = CONF_FIRST[b.key] ?? 2;
|
||||
if (ra !== rb) return ra - rb;
|
||||
return a.label.localeCompare(b.label);
|
||||
});
|
||||
}
|
||||
|
||||
// OpsLog's own card. Kept out of CONFIRMATIONS on purpose — that list maps QSO
|
||||
// columns and this channel is backed by ADIF extras — but it still belongs in
|
||||
// the channel picker and the status table alongside the rest.
|
||||
@@ -756,15 +769,19 @@ export function QSOEditModal({ qso, onSave, onDelete, onClose, countries = [], b
|
||||
<Select value={confSel} onValueChange={setConfSel}>
|
||||
<SelectTrigger><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
{CONFIRMATIONS.map((c) => <SelectItem key={c.key} value={c.key}>{CONF_LABEL_KEYS[c.key] ? t(CONF_LABEL_KEYS[c.key]) : c.label}</SelectItem>)}
|
||||
{/* Listed here but NOT in CONFIRMATIONS: that table maps
|
||||
{confOrder([
|
||||
...CONFIRMATIONS.map((c) => ({ key: c.key, label: CONF_LABEL_KEYS[c.key] ? t(CONF_LABEL_KEYS[c.key]) : c.label })),
|
||||
{ key: OPSLOG_CONF, label: t('qedit.confOpsLog') },
|
||||
{ key: HAMLOG_CONF, label: 'HAMLOG.online' },
|
||||
{ key: HAMQTH_CONF, label: 'HamQTH' },
|
||||
]).map((c) => <SelectItem key={c.key} value={c.key}>{c.label}</SelectItem>)}
|
||||
{/* The three above that are NOT in CONFIRMATIONS — the
|
||||
QSO columns, and this channel lives in the ADIF
|
||||
extras. It gets its own editor below rather than the
|
||||
generic sent/received/date grid, which has no field
|
||||
to bind to. */}
|
||||
<SelectItem value={OPSLOG_CONF}>{t('qedit.confOpsLog')}</SelectItem>
|
||||
<SelectItem value={HAMLOG_CONF}>HAMLOG.online</SelectItem>
|
||||
<SelectItem value={HAMQTH_CONF}>HamQTH</SelectItem>
|
||||
OpsLog card, HAMLOG.online and HamQTH — are backed by
|
||||
ADIF extras rather than QSO columns, and each gets its
|
||||
own editor below instead of the generic
|
||||
sent/received/date grid, which has no field to bind
|
||||
to. */}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
@@ -865,37 +882,32 @@ export function QSOEditModal({ qso, onSave, onDelete, onClose, countries = [], b
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{CONFIRMATIONS.map((c) => (
|
||||
{/* The extras-backed channels (OpsLog card,
|
||||
HAMLOG.online, HamQTH) sit in the same ordered list
|
||||
as the column-backed ones: the reader is looking for
|
||||
a name, not for a storage detail. A dash in RECEIVED
|
||||
means the channel has nothing to receive — Club Log
|
||||
and HamQTH publish no confirmations — which is not
|
||||
the same statement as "N". */}
|
||||
{confOrder([
|
||||
...CONFIRMATIONS.map((c) => ({
|
||||
key: c.key,
|
||||
label: CONF_LABEL_KEYS[c.key] ? t(CONF_LABEL_KEYS[c.key]) : c.label,
|
||||
sent: val(c.sent),
|
||||
rcvd: c.rcvd ? val(c.rcvd) : null,
|
||||
})),
|
||||
{ key: OPSLOG_CONF, label: t('qedit.confOpsLog'), sent: opslogQslSent ? 'Y' : 'N', rcvd: qslReceived ? 'Y' : 'N' },
|
||||
{ key: HAMLOG_CONF, label: 'HAMLOG.online', sent: exVal(HAMLOG_KEYS.sent), rcvd: exVal(HAMLOG_KEYS.rcvd) },
|
||||
{ key: HAMQTH_CONF, label: 'HamQTH', sent: exVal(HAMQTH_KEYS.sent), rcvd: null },
|
||||
]).map((c) => (
|
||||
<tr key={c.key} className="text-xs">
|
||||
<td className="font-medium pr-3 py-0.5 whitespace-nowrap">{CONF_LABEL_KEYS[c.key] ? t(CONF_LABEL_KEYS[c.key]) : c.label}</td>
|
||||
<td className="w-24"><StatusCell value={val(c.sent)} /></td>
|
||||
<td className="w-24">{c.rcvd ? <StatusCell value={val(c.rcvd)} /> : <span className="block text-center text-[11px] text-muted-foreground">—</span>}</td>
|
||||
<td className="font-medium pr-3 py-0.5 whitespace-nowrap">{c.label}</td>
|
||||
<td className="w-24"><StatusCell value={c.sent} /></td>
|
||||
<td className="w-24">{c.rcvd === null
|
||||
? <span className="block text-center text-[11px] text-muted-foreground">—</span>
|
||||
: <StatusCell value={c.rcvd} />}</td>
|
||||
</tr>
|
||||
))}
|
||||
{/* OpsLog's own card, read from the ADIF extras rather
|
||||
than a QSO column — hence a hand-written row instead
|
||||
of a CONFIRMATIONS entry. "Sent" is stamped by OpsLog
|
||||
when the card actually goes out, so it stays
|
||||
read-only here: an operator ticking it by hand would
|
||||
be recording something that never happened. */}
|
||||
<tr className="text-xs">
|
||||
<td className="font-medium pr-3 py-0.5 whitespace-nowrap">{t('qedit.confOpsLog')}</td>
|
||||
<td className="w-24"><StatusCell value={opslogQslSent ? 'Y' : 'N'} /></td>
|
||||
<td className="w-24"><StatusCell value={qslReceived ? 'Y' : 'N'} /></td>
|
||||
</tr>
|
||||
{/* HAMLOG.online — extras again, same hand-written row. */}
|
||||
<tr className="text-xs">
|
||||
<td className="font-medium pr-3 py-0.5 whitespace-nowrap">HAMLOG.online</td>
|
||||
<td className="w-24"><StatusCell value={exVal(HAMLOG_KEYS.sent)} /></td>
|
||||
<td className="w-24"><StatusCell value={exVal(HAMLOG_KEYS.rcvd)} /></td>
|
||||
</tr>
|
||||
{/* HamQTH — sent only; the dash says there is nothing
|
||||
to receive, not that nothing was received. */}
|
||||
<tr className="text-xs">
|
||||
<td className="font-medium pr-3 py-0.5 whitespace-nowrap">HamQTH</td>
|
||||
<td className="w-24"><StatusCell value={exVal(HAMQTH_KEYS.sent)} /></td>
|
||||
<td className="w-24"><span className="block text-center text-[11px] text-muted-foreground">—</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user