changemaker.lite/api/src/modules/volunteer-dashboard/volunteer-dashboard.routes.ts
bunker-admin ed011a762b Add action-campaigns module + volunteer-dashboard aggregator
ActionCampaign service exposes admin CRUD plus a per-user composer
(getActiveForUser) that fans out a per-step completion check against
the existing per-user model for each ActionStepKind: VideoView for
WATCH_VIDEO, CampaignEmail for SUBMIT_INFLUENCE, PetitionSignature
for SIGN_PETITION (matched by signer email), Ticket for RSVP_EVENT,
ShiftSignup for SIGNUP_SHIFT, ChallengeTeamMember for JOIN_CHALLENGE.
CUSTOM and VISIT_LINK steps complete only via explicit self-report.
An existing ActionStepCompletion row also short-circuits the check
so manual marking and idempotency both work.

Volunteer dashboard aggregator at GET /api/volunteer/dashboard
composes the active campaign with the user's profile, referral info,
upcoming featured event, training shifts (Shift.kind='TRAINING'),
ticketed events the user holds, an engagement-counter point total
(placeholder until the Redis engagement score is wired in), and
resources tagged 'volunteer-resource' across Document/Video/Photo.

Bunker Admin
2026-04-11 10:20:26 -06:00

23 lines
688 B
TypeScript

import { Router, Request, Response, NextFunction } from 'express';
import { volunteerDashboardService } from './volunteer-dashboard.service';
import { authenticate } from '../../middleware/auth.middleware';
import { AppError } from '../../middleware/error-handler';
const router = Router();
router.get(
'/dashboard',
authenticate,
async (req: Request, res: Response, next: NextFunction) => {
try {
const data = await volunteerDashboardService.getDashboard(req.user!.id);
if (!data) throw new AppError(404, 'User not found', 'USER_NOT_FOUND');
res.json(data);
} catch (err) {
next(err);
}
},
);
export { router as volunteerDashboardRouter };