57 lines
2.1 KiB
TypeScript
57 lines
2.1 KiB
TypeScript
import { Router, Response, NextFunction } from 'express';
|
|
import { body, validationResult } from 'express-validator';
|
|
import prisma from '../lib/prisma';
|
|
import { optionalAuth, authenticate, requireRole, AuthRequest } from '../middleware/auth';
|
|
|
|
const router = Router();
|
|
|
|
// POST /api/donations — public (guest) or authenticated
|
|
// Stripe integration stub: stores intent, returns client_secret placeholder
|
|
router.post('/', optionalAuth,
|
|
[
|
|
body('amount').isFloat({ min: 1 }).withMessage('Amount must be at least $1'),
|
|
body('campaign').optional().isIn(['land_preservation', 'volunteer_equipment', 'general']),
|
|
],
|
|
async (req: AuthRequest, res: Response, next: NextFunction) => {
|
|
const errors = validationResult(req);
|
|
if (!errors.isEmpty()) { res.status(422).json({ errors: errors.array() }); return; }
|
|
|
|
try {
|
|
const { amount, campaign } = req.body;
|
|
|
|
// STUB: In production, create a Stripe PaymentIntent here and return client_secret
|
|
// const intent = await stripe.paymentIntents.create({ amount: Math.round(amount * 100), currency: 'usd' });
|
|
const stripe_payment_id = `pi_stub_${Date.now()}`;
|
|
|
|
const donation = await prisma.donation.create({
|
|
data: {
|
|
donor_id: req.user?.userId ?? null,
|
|
amount: parseFloat(amount),
|
|
campaign: campaign || 'general',
|
|
stripe_payment_id,
|
|
},
|
|
});
|
|
|
|
res.status(201).json({
|
|
donation,
|
|
// stub: replace with real Stripe client_secret for frontend confirmation
|
|
client_secret: `${stripe_payment_id}_secret`,
|
|
message: 'Stripe integration pending — payment recorded as stub',
|
|
});
|
|
} catch (err) { next(err); }
|
|
}
|
|
);
|
|
|
|
// GET /api/donations — admin only
|
|
router.get('/', authenticate, requireRole('admin'), async (_req: AuthRequest, res: Response, next: NextFunction) => {
|
|
try {
|
|
const donations = await prisma.donation.findMany({
|
|
include: { donor: { select: { id: true, name: true, email: true } } },
|
|
orderBy: { created_at: 'desc' },
|
|
});
|
|
res.json(donations);
|
|
} catch (err) { next(err); }
|
|
});
|
|
|
|
export default router;
|