Implement event completion workflow (Task 14)

- Add completeEvent endpoint to backend API
- Create EventCompletionForm component with litter quantity input and photo upload
- Update EventDetailModal to show completion form for organizers
- Add isOrganizer check in EventsPage
- Update event service to support completion
- Display completion data (litter collected, photos) for completed events
This commit is contained in:
2025-11-16 20:21:47 +00:00
parent ec70baa498
commit c1f362a604
9 changed files with 295 additions and 6 deletions

View File

@@ -343,4 +343,66 @@ export const eventController = {
});
}
},
// Complete event
async completeEvent(req: AuthRequest, res: Response) {
try {
const clerkId = req.userId;
if (!clerkId) {
return res.status(401).json({
code: 'UNAUTHORIZED',
message: 'User not authenticated',
timestamp: new Date().toISOString(),
});
}
const userId = await findOrCreateUser(clerkId);
const { id } = req.params;
const event = await eventService.getEventById(id);
if (!event) {
return res.status(404).json({
code: 'EVENT_NOT_FOUND',
message: 'Event not found',
timestamp: new Date().toISOString(),
});
}
// Check if user is the organizer
if (event.organizerId !== userId) {
return res.status(403).json({
code: 'FORBIDDEN',
message: 'Only the event organizer can complete this event',
timestamp: new Date().toISOString(),
});
}
const { litterCollected, photos } = req.body;
// Validation
if (litterCollected === undefined || litterCollected === null) {
return res.status(400).json({
code: 'VALIDATION_ERROR',
message: 'litterCollected is required',
timestamp: new Date().toISOString(),
});
}
const completedEvent = await eventService.completeEvent(id, {
litterCollected: parseFloat(litterCollected),
photos: photos || [],
});
res.json(completedEvent);
} catch (error: any) {
console.error('Error completing event:', error);
res.status(500).json({
code: 'COMPLETE_EVENT_ERROR',
message: 'Failed to complete event',
details: error.message,
timestamp: new Date().toISOString(),
});
}
},
};