- Server: Express.js with 13 API route files (auth, regulations, contacts, calendar, truck stops, bridges, weigh stations, alerts, load board, escort locator, orders, documents, contributions) - Database: PostgreSQL with Prisma ORM, 15 models covering all modules - Auth: JWT + bcrypt with role-based access control (driver/carrier/escort/admin) - Geospatial: Haversine distance filtering on truck stops, bridges, escorts - Seed script: Imports all existing mock data (51 states, contacts, equipment, truck stops, bridges, weigh stations, alerts, seasonal restrictions) - Frontend: All 10 data-driven pages now fetch from /api instead of mock-data.js - API client (api.js): Compatibility layer that transforms API responses to match existing frontend rendering code, minimizing page-level changes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
55 lines
1.3 KiB
JavaScript
55 lines
1.3 KiB
JavaScript
const express = require('express');
|
|
const prisma = require('../config/db');
|
|
|
|
const router = express.Router();
|
|
|
|
// GET /api/alerts?state=...&type=...&severity=...
|
|
router.get('/', async (req, res, next) => {
|
|
try {
|
|
const { state, type, severity } = req.query;
|
|
const where = {};
|
|
|
|
if (state) {
|
|
where.state = { abbr: state.toUpperCase() };
|
|
}
|
|
if (type) {
|
|
where.type = type;
|
|
}
|
|
if (severity) {
|
|
where.severity = severity;
|
|
}
|
|
|
|
// Only show active alerts (endsAt is null or in the future)
|
|
where.OR = [
|
|
{ endsAt: null },
|
|
{ endsAt: { gte: new Date() } },
|
|
];
|
|
|
|
const alerts = await prisma.alert.findMany({
|
|
where,
|
|
include: { state: { select: { name: true, abbr: true } } },
|
|
orderBy: [{ severity: 'desc' }, { startsAt: 'desc' }],
|
|
});
|
|
|
|
res.json(alerts);
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
// GET /api/alerts/:id
|
|
router.get('/:id', async (req, res, next) => {
|
|
try {
|
|
const alert = await prisma.alert.findUnique({
|
|
where: { id: req.params.id },
|
|
include: { state: { select: { name: true, abbr: true } } },
|
|
});
|
|
if (!alert) return res.status(404).json({ error: 'Alert not found.' });
|
|
res.json(alert);
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|