feat: add QSO page filters and fix DXCC entity priority

- Add confirmation type filter (LoTW Only, DCL Only, Both, None)
- Add search box for callsign, entity, and grid square
- Rename "All Confirmation" to "All QSOs" for clarity
- Fix exclusive filter logic using separate SQL conditions
- Add debug logging for filter troubleshooting
- Implement DXCC priority: LoTW > DCL
- Document QSO page filters and DXCC handling in CLAUDE.md

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-19 08:01:59 +01:00
parent b422c20463
commit 8d47e6e4ad
3 changed files with 101 additions and 9 deletions

View File

@@ -322,6 +322,8 @@ export async function syncQSOs(userId, lotwUsername, lotwPassword, sinceDate = n
export async function getUserQSOs(userId, filters = {}, options = {}) {
const { page = 1, limit = 100 } = options;
logger.debug('getUserQSOs called', { userId, filters, options });
const conditions = [eq(qsos.userId, userId)];
if (filters.band) conditions.push(eq(qsos.band, filters.band));
@@ -330,20 +332,31 @@ export async function getUserQSOs(userId, filters = {}, options = {}) {
// Confirmation type filter: lotw, dcl, both, none
if (filters.confirmationType) {
logger.debug('Applying confirmation type filter', { confirmationType: filters.confirmationType });
if (filters.confirmationType === 'lotw') {
// LoTW only: Confirmed by LoTW but NOT by DCL
conditions.push(eq(qsos.lotwQslRstatus, 'Y'));
conditions.push(
sql`(${qsos.dclQslRstatus} IS NULL OR ${qsos.dclQslRstatus} != 'Y')`
);
} else if (filters.confirmationType === 'dcl') {
// DCL only: Confirmed by DCL but NOT by LoTW
conditions.push(eq(qsos.dclQslRstatus, 'Y'));
conditions.push(
sql`(${qsos.lotwQslRstatus} IS NULL OR ${qsos.lotwQslRstatus} != 'Y')`
);
} else if (filters.confirmationType === 'both') {
conditions.push(and(
eq(qsos.lotwQslRstatus, 'Y'),
eq(qsos.dclQslRstatus, 'Y')
));
// Both confirmed: Confirmed by LoTW AND DCL
conditions.push(eq(qsos.lotwQslRstatus, 'Y'));
conditions.push(eq(qsos.dclQslRstatus, 'Y'));
} else if (filters.confirmationType === 'none') {
conditions.push(and(
sql`${qsos.lotwQslRstatus} IS NULL OR ${qsos.lotwQslRstatus} != 'Y'`,
sql`${qsos.dclQslRstatus} IS NULL OR ${qsos.dclQslRstatus} != 'Y'`
));
// Not confirmed: Not confirmed by LoTW AND not confirmed by DCL
conditions.push(
sql`(${qsos.lotwQslRstatus} IS NULL OR ${qsos.lotwQslRstatus} != 'Y')`
);
conditions.push(
sql`(${qsos.dclQslRstatus} IS NULL OR ${qsos.dclQslRstatus} != 'Y')`
);
}
}

View File

@@ -565,7 +565,7 @@
</select>
<select bind:value={filters.confirmationType} on:change={applyFilters} class="confirmation-filter">
<option value="all">All Confirmation</option>
<option value="all">All QSOs</option>
<option value="lotw">LoTW Only</option>
<option value="dcl">DCL Only</option>
<option value="both">Both Confirmed</option>