Improve guard scheduling with time slot conflict detection and assignment

Add API endpoints for retrieving guard availability with date range filtering and for creating shift assignments with planned start and end times, including validation and conflict detection.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: e5565357-90e1-419f-b9a8-6ee8394636df
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/e5565357-90e1-419f-b9a8-6ee8394636df/ZZOTK7r
This commit is contained in:
marco370 2025-10-21 06:38:25 +00:00
parent c72125c68f
commit c95bf04abf

View File

@ -294,26 +294,33 @@ export async function registerRoutes(app: Express): Promise<Server> {
} }
}); });
// Get guards availability for general planning // Get guards availability for general planning with time slot conflict detection
app.get("/api/guards/availability", isAuthenticated, async (req, res) => { app.get("/api/guards/availability", isAuthenticated, async (req, res) => {
try { try {
const { weekStart, siteId, location } = req.query; const { start, end, siteId, location } = req.query;
if (!weekStart || !siteId || !location) { if (!start || !end || !siteId || !location) {
return res.status(400).json({ return res.status(400).json({
message: "Missing required parameters: weekStart, siteId, location" message: "Missing required parameters: start, end, siteId, location"
}); });
} }
const weekStartDate = parseISO(weekStart as string); const startDate = parseISO(start as string);
if (!isValid(weekStartDate)) { const endDate = parseISO(end as string);
return res.status(400).json({ message: "Invalid weekStart date format" });
if (!isValid(startDate) || !isValid(endDate)) {
return res.status(400).json({ message: "Invalid date format for start or end" });
}
if (endDate <= startDate) {
return res.status(400).json({ message: "End time must be after start time" });
} }
const availability = await storage.getGuardsAvailability( const availability = await storage.getGuardsAvailability(
weekStartDate,
siteId as string, siteId as string,
location as string location as string,
startDate,
endDate
); );
res.json(availability); res.json(availability);
@ -1681,6 +1688,48 @@ export async function registerRoutes(app: Express): Promise<Server> {
} }
}); });
// Create shift assignment with planned time slots
app.post("/api/shifts/:shiftId/assignments", isAuthenticated, async (req, res) => {
try {
const { shiftId } = req.params;
const { guardId, plannedStartTime, plannedEndTime } = req.body;
if (!guardId || !plannedStartTime || !plannedEndTime) {
return res.status(400).json({
message: "Missing required fields: guardId, plannedStartTime, plannedEndTime"
});
}
// Validate times
const startDate = new Date(plannedStartTime);
const endDate = new Date(plannedEndTime);
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
return res.status(400).json({ message: "Invalid date format for plannedStartTime or plannedEndTime" });
}
if (endDate <= startDate) {
return res.status(400).json({ message: "plannedEndTime must be after plannedStartTime" });
}
// Create assignment
const assignment = await storage.createShiftAssignment({
shiftId,
guardId,
plannedStartTime: startDate,
plannedEndTime: endDate,
});
res.json(assignment);
} catch (error: any) {
console.error("Error creating shift assignment with time slot:", error);
if (error.message?.includes('overlap') || error.message?.includes('conflict')) {
return res.status(409).json({ message: error.message });
}
res.status(500).json({ message: "Failed to create shift assignment" });
}
});
// ============= NOTIFICATION ROUTES ============= // ============= NOTIFICATION ROUTES =============
app.get("/api/notifications", isAuthenticated, async (req: any, res) => { app.get("/api/notifications", isAuthenticated, async (req: any, res) => {
try { try {