Add awards system with progress tracking
Implement awards display with progress calculation based on QSO data. ## Backend - Add awards service with progress calculation logic - Support for DXCC, WAS, VUCC, and satellite awards - Filter QSOs by band, mode, and other criteria - Calculate worked/confirmed entities per award - API endpoints: - GET /api/awards - List all awards - GET /api/awards/:id/progress - Get award progress - GET /api/awards/:id/entities - Get detailed entity breakdown ## Frontend - Create awards listing page with progress cards - Add Awards link to navigation bar - Display award progress bars with worked/confirmed counts - Link to individual award detail pages (to be implemented) - Copy award definitions to static folder ## Award Definitions - DXCC Mixed Mode (100 entities) - DXCC CW (100 entities, CW only) - WAS Mixed Mode (50 states) - VUCC Satellite (100 grids) - RS-44 Satellite Award (100 QSOs) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,11 @@ import {
|
||||
getUserActiveJob,
|
||||
getUserJobs,
|
||||
} from './services/job-queue.service.js';
|
||||
import {
|
||||
getAllAwards,
|
||||
getAwardProgressDetails,
|
||||
getAwardEntityBreakdown,
|
||||
} from './services/awards.service.js';
|
||||
|
||||
/**
|
||||
* Main backend application
|
||||
@@ -478,6 +483,89 @@ const app = new Elysia()
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* GET /api/awards
|
||||
* Get all available awards (requires authentication)
|
||||
*/
|
||||
.get('/api/awards', async ({ user, set }) => {
|
||||
if (!user) {
|
||||
set.status = 401;
|
||||
return { success: false, error: 'Unauthorized' };
|
||||
}
|
||||
|
||||
try {
|
||||
const awards = await getAllAwards();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
awards,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error('Error fetching awards', { error: error.message });
|
||||
set.status = 500;
|
||||
return {
|
||||
success: false,
|
||||
error: 'Failed to fetch awards',
|
||||
};
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* GET /api/awards/:awardId/progress
|
||||
* Get award progress for user (requires authentication)
|
||||
*/
|
||||
.get('/api/awards/:awardId/progress', async ({ user, params, set }) => {
|
||||
if (!user) {
|
||||
set.status = 401;
|
||||
return { success: false, error: 'Unauthorized' };
|
||||
}
|
||||
|
||||
try {
|
||||
const { awardId } = params;
|
||||
const progress = await getAwardProgressDetails(user.id, awardId);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
...progress,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error('Error calculating award progress', { error: error.message });
|
||||
set.status = 500;
|
||||
return {
|
||||
success: false,
|
||||
error: error.message || 'Failed to calculate award progress',
|
||||
};
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* GET /api/awards/:awardId/entities
|
||||
* Get detailed entity breakdown for an award (requires authentication)
|
||||
*/
|
||||
.get('/api/awards/:awardId/entities', async ({ user, params, set }) => {
|
||||
if (!user) {
|
||||
set.status = 401;
|
||||
return { success: false, error: 'Unauthorized' };
|
||||
}
|
||||
|
||||
try {
|
||||
const { awardId } = params;
|
||||
const breakdown = await getAwardEntityBreakdown(user.id, awardId);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
...breakdown,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error('Error fetching award entities', { error: error.message });
|
||||
set.status = 500;
|
||||
return {
|
||||
success: false,
|
||||
error: error.message || 'Failed to fetch award entities',
|
||||
};
|
||||
}
|
||||
})
|
||||
|
||||
// Health check endpoint
|
||||
.get('/api/health', () => ({
|
||||
status: 'ok',
|
||||
|
||||
Reference in New Issue
Block a user