import type { Express } from "express"; import { createServer, type Server } from "http"; import { storage } from "./storage"; import { setupAuth, isAuthenticated } from "./replitAuth"; import { db } from "./db"; import { guards, certifications, sites, shifts, shiftAssignments, users } from "@shared/schema"; import { eq } from "drizzle-orm"; import { differenceInDays } from "date-fns"; export async function registerRoutes(app: Express): Promise { // Auth middleware await setupAuth(app); // ============= AUTH ROUTES ============= app.get("/api/auth/user", isAuthenticated, async (req: any, res) => { try { const userId = req.user.claims.sub; const user = await storage.getUser(userId); res.json(user); } catch (error) { console.error("Error fetching user:", error); res.status(500).json({ message: "Failed to fetch user" }); } }); // ============= GUARD ROUTES ============= app.get("/api/guards", isAuthenticated, async (req, res) => { try { const allGuards = await storage.getAllGuards(); // Fetch related data for each guard const guardsWithDetails = await Promise.all( allGuards.map(async (guard) => { const certs = await storage.getCertificationsByGuard(guard.id); const user = guard.userId ? await storage.getUser(guard.userId) : undefined; // Update certification status based on expiry date for (const cert of certs) { const daysUntilExpiry = differenceInDays(new Date(cert.expiryDate), new Date()); let newStatus: "valid" | "expiring_soon" | "expired" = "valid"; if (daysUntilExpiry < 0) { newStatus = "expired"; } else if (daysUntilExpiry <= 30) { newStatus = "expiring_soon"; } if (cert.status !== newStatus) { await storage.updateCertificationStatus(cert.id, newStatus); cert.status = newStatus; } } return { ...guard, certifications: certs, user, }; }) ); res.json(guardsWithDetails); } catch (error) { console.error("Error fetching guards:", error); res.status(500).json({ message: "Failed to fetch guards" }); } }); app.post("/api/guards", isAuthenticated, async (req, res) => { try { const guard = await storage.createGuard(req.body); res.json(guard); } catch (error) { console.error("Error creating guard:", error); res.status(500).json({ message: "Failed to create guard" }); } }); // ============= CERTIFICATION ROUTES ============= app.post("/api/certifications", isAuthenticated, async (req, res) => { try { const cert = await storage.createCertification(req.body); res.json(cert); } catch (error) { console.error("Error creating certification:", error); res.status(500).json({ message: "Failed to create certification" }); } }); // ============= SITE ROUTES ============= app.get("/api/sites", isAuthenticated, async (req, res) => { try { const allSites = await storage.getAllSites(); res.json(allSites); } catch (error) { console.error("Error fetching sites:", error); res.status(500).json({ message: "Failed to fetch sites" }); } }); app.post("/api/sites", isAuthenticated, async (req, res) => { try { const site = await storage.createSite(req.body); res.json(site); } catch (error) { console.error("Error creating site:", error); res.status(500).json({ message: "Failed to create site" }); } }); // ============= SHIFT ROUTES ============= app.get("/api/shifts", isAuthenticated, async (req, res) => { try { const allShifts = await storage.getAllShifts(); // Fetch related data for each shift const shiftsWithDetails = await Promise.all( allShifts.map(async (shift) => { const site = await storage.getSite(shift.siteId); const assignments = await storage.getShiftAssignments(shift.id); // Fetch guard details for each assignment const assignmentsWithGuards = await Promise.all( assignments.map(async (assignment) => { const guard = await storage.getGuard(assignment.guardId); const certs = guard ? await storage.getCertificationsByGuard(guard.id) : []; const user = guard?.userId ? await storage.getUser(guard.userId) : undefined; return { ...assignment, guard: guard ? { ...guard, certifications: certs, user, } : null, }; }) ); return { ...shift, site: site!, assignments: assignmentsWithGuards.filter(a => a.guard !== null), }; }) ); res.json(shiftsWithDetails); } catch (error) { console.error("Error fetching shifts:", error); res.status(500).json({ message: "Failed to fetch shifts" }); } }); app.get("/api/shifts/active", isAuthenticated, async (req, res) => { try { const activeShifts = await storage.getActiveShifts(); // Fetch related data for each shift const shiftsWithDetails = await Promise.all( activeShifts.map(async (shift) => { const site = await storage.getSite(shift.siteId); const assignments = await storage.getShiftAssignments(shift.id); // Fetch guard details for each assignment const assignmentsWithGuards = await Promise.all( assignments.map(async (assignment) => { const guard = await storage.getGuard(assignment.guardId); const certs = guard ? await storage.getCertificationsByGuard(guard.id) : []; const user = guard?.userId ? await storage.getUser(guard.userId) : undefined; return { ...assignment, guard: guard ? { ...guard, certifications: certs, user, } : null, }; }) ); return { ...shift, site: site!, assignments: assignmentsWithGuards.filter(a => a.guard !== null), }; }) ); res.json(shiftsWithDetails); } catch (error) { console.error("Error fetching active shifts:", error); res.status(500).json({ message: "Failed to fetch active shifts" }); } }); app.post("/api/shifts", isAuthenticated, async (req, res) => { try { const shift = await storage.createShift(req.body); res.json(shift); } catch (error) { console.error("Error creating shift:", error); res.status(500).json({ message: "Failed to create shift" }); } }); app.patch("/api/shifts/:id/status", isAuthenticated, async (req, res) => { try { await storage.updateShiftStatus(req.params.id, req.body.status); res.json({ success: true }); } catch (error) { console.error("Error updating shift status:", error); res.status(500).json({ message: "Failed to update shift status" }); } }); // ============= SHIFT ASSIGNMENT ROUTES ============= app.post("/api/shift-assignments", isAuthenticated, async (req, res) => { try { const assignment = await storage.createShiftAssignment(req.body); res.json(assignment); } catch (error) { console.error("Error creating shift assignment:", error); res.status(500).json({ message: "Failed to create shift assignment" }); } }); // ============= NOTIFICATION ROUTES ============= app.get("/api/notifications", isAuthenticated, async (req: any, res) => { try { const userId = req.user.claims.sub; const userNotifications = await storage.getNotificationsByUser(userId); res.json(userNotifications); } catch (error) { console.error("Error fetching notifications:", error); res.status(500).json({ message: "Failed to fetch notifications" }); } }); app.patch("/api/notifications/:id/read", isAuthenticated, async (req, res) => { try { await storage.markNotificationAsRead(req.params.id); res.json({ success: true }); } catch (error) { console.error("Error marking notification as read:", error); res.status(500).json({ message: "Failed to mark notification as read" }); } }); const httpServer = createServer(app); return httpServer; }