diff --git a/src/backend/services/dcl.service.js b/src/backend/services/dcl.service.js index b99391b..a348212 100644 --- a/src/backend/services/dcl.service.js +++ b/src/backend/services/dcl.service.js @@ -193,6 +193,8 @@ export async function syncQSOs(userId, dclApiKey, sinceDate = null, jobId = null let addedCount = 0; let updatedCount = 0; const errors = []; + const addedQSOs = []; + const updatedQSOs = []; for (let i = 0; i < adifQSOs.length; i++) { const adifQSO = adifQSOs[i]; @@ -230,10 +232,24 @@ export async function syncQSOs(userId, dclApiKey, sinceDate = null, jobId = null }) .where(eq(qsos.id, existing[0].id)); updatedCount++; + // Track updated QSO (CALL and DATE) + updatedQSOs.push({ + callsign: dbQSO.callsign, + date: dbQSO.qsoDate, + band: dbQSO.band, + mode: dbQSO.mode, + }); } else { // Insert new QSO await db.insert(qsos).values(dbQSO); addedCount++; + // Track added QSO (CALL and DATE) + addedQSOs.push({ + callsign: dbQSO.callsign, + date: dbQSO.qsoDate, + band: dbQSO.band, + mode: dbQSO.mode, + }); } // Update job progress every 10 QSOs @@ -258,6 +274,8 @@ export async function syncQSOs(userId, dclApiKey, sinceDate = null, jobId = null total: adifQSOs.length, added: addedCount, updated: updatedCount, + addedQSOs, + updatedQSOs, confirmed: adifQSOs.filter(q => q.dcl_qsl_rcvd === 'Y').length, errors: errors.length > 0 ? errors : undefined, }; diff --git a/src/backend/services/lotw.service.js b/src/backend/services/lotw.service.js index 483eaf5..df8be76 100644 --- a/src/backend/services/lotw.service.js +++ b/src/backend/services/lotw.service.js @@ -223,6 +223,8 @@ export async function syncQSOs(userId, lotwUsername, lotwPassword, sinceDate = n let addedCount = 0; let updatedCount = 0; const errors = []; + const addedQSOs = []; + const updatedQSOs = []; for (let i = 0; i < adifQSOs.length; i++) { const qsoData = adifQSOs[i]; @@ -254,9 +256,23 @@ export async function syncQSOs(userId, lotwUsername, lotwPassword, sinceDate = n }) .where(eq(qsos.id, existing[0].id)); updatedCount++; + // Track updated QSO (CALL and DATE) + updatedQSOs.push({ + callsign: dbQSO.callsign, + date: dbQSO.qsoDate, + band: dbQSO.band, + mode: dbQSO.mode, + }); } else { await db.insert(qsos).values(dbQSO); addedCount++; + // Track added QSO (CALL and DATE) + addedQSOs.push({ + callsign: dbQSO.callsign, + date: dbQSO.qsoDate, + band: dbQSO.band, + mode: dbQSO.mode, + }); } // Update job progress every 10 QSOs @@ -279,6 +295,8 @@ export async function syncQSOs(userId, lotwUsername, lotwPassword, sinceDate = n total: adifQSOs.length, added: addedCount, updated: updatedCount, + addedQSOs, + updatedQSOs, errors: errors.length > 0 ? errors : undefined, }; } diff --git a/src/frontend/src/routes/qsos/+page.svelte b/src/frontend/src/routes/qsos/+page.svelte index a0aef53..8573962 100644 --- a/src/frontend/src/routes/qsos/+page.svelte +++ b/src/frontend/src/routes/qsos/+page.svelte @@ -306,6 +306,68 @@ {/if} + + {#if syncResult.success && (syncResult.addedQSOs?.length > 0 || syncResult.updatedQSOs?.length > 0)} +
+

Import Log

+ + {#if syncResult.addedQSOs && syncResult.addedQSOs.length > 0} +
+

New QSOs ({syncResult.addedQSOs.length})

+
+ + + + + + + + + + + {#each syncResult.addedQSOs as qso} + + + + + + + {/each} + +
CallsignDateBandMode
{qso.callsign}{formatDate(qso.date)}{qso.band || '-'}{qso.mode || '-'}
+
+
+ {/if} + + {#if syncResult.updatedQSOs && syncResult.updatedQSOs.length > 0} +
+

Updated QSOs ({syncResult.updatedQSOs.length})

+
+ + + + + + + + + + + {#each syncResult.updatedQSOs as qso} + + + + + + + {/each} + +
CallsignDateBandMode
{qso.callsign}{formatDate(qso.date)}{qso.band || '-'}{qso.mode || '-'}
+
+
+ {/if} +
+ {/if} {/if} {#if showDeleteConfirm} @@ -845,4 +907,72 @@ opacity: 0.5; cursor: not-allowed; } + + .import-log { + background: white; + border: 1px solid #e0e0e0; + border-radius: 8px; + padding: 1.5rem; + margin-top: 1rem; + } + + .import-log h3 { + margin: 0 0 1rem 0; + color: #333; + font-size: 1.25rem; + } + + .log-section { + margin-bottom: 1.5rem; + } + + .log-section:last-child { + margin-bottom: 0; + } + + .log-section h4 { + margin: 0 0 0.75rem 0; + color: #555; + font-size: 1rem; + font-weight: 600; + } + + .log-table-container { + overflow-x: auto; + border: 1px solid #e0e0e0; + border-radius: 4px; + } + + .log-table { + width: 100%; + border-collapse: collapse; + font-size: 0.9rem; + } + + .log-table th, + .log-table td { + padding: 0.5rem 0.75rem; + text-align: left; + border-bottom: 1px solid #e0e0e0; + } + + .log-table th { + background-color: #f8f9fa; + font-weight: 600; + color: #333; + font-size: 0.85rem; + } + + .log-table tr:last-child td { + border-bottom: none; + } + + .log-table tr:hover { + background-color: #f8f9fa; + } + + .log-table .callsign { + font-weight: 600; + color: #4a90e2; + }