"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); class ScheduleValidationService { // Validate a single schedule event validateEvent(event, isEdit = false) { const errors = []; const now = new Date(); const startTime = new Date(event.startTime); const endTime = new Date(event.endTime); // 1. Check if dates are valid if (isNaN(startTime.getTime())) { errors.push({ field: 'startTime', message: 'Start time is not a valid date', code: 'INVALID_START_DATE' }); } if (isNaN(endTime.getTime())) { errors.push({ field: 'endTime', message: 'End time is not a valid date', code: 'INVALID_END_DATE' }); } // If dates are invalid, return early if (errors.length > 0) { return errors; } // 2. Check if start time is in the future (with 5-minute grace period for edits) const graceMinutes = isEdit ? 5 : 0; const minimumStartTime = new Date(now.getTime() + (graceMinutes * 60 * 1000)); if (startTime < minimumStartTime) { errors.push({ field: 'startTime', message: isEdit ? 'Start time must be at least 5 minutes in the future for edits' : 'Start time must be in the future', code: 'START_TIME_IN_PAST' }); } // 3. Check if end time is after start time if (endTime <= startTime) { errors.push({ field: 'endTime', message: 'End time must be after start time', code: 'END_BEFORE_START' }); } // 4. Check minimum event duration (5 minutes) const durationMinutes = (endTime.getTime() - startTime.getTime()) / (1000 * 60); if (durationMinutes < 5) { errors.push({ field: 'endTime', message: 'Event must be at least 5 minutes long', code: 'DURATION_TOO_SHORT' }); } // 5. Check maximum event duration (24 hours) if (durationMinutes > (24 * 60)) { errors.push({ field: 'endTime', message: 'Event cannot be longer than 24 hours', code: 'DURATION_TOO_LONG' }); } // 6. Check if end time is in the future if (endTime < now) { errors.push({ field: 'endTime', message: 'End time must be in the future', code: 'END_TIME_IN_PAST' }); } // 7. Validate required fields if (!event.title || event.title.trim().length === 0) { errors.push({ field: 'title', message: 'Event title is required', code: 'TITLE_REQUIRED' }); } if (!event.location || event.location.trim().length === 0) { errors.push({ field: 'location', message: 'Event location is required', code: 'LOCATION_REQUIRED' }); } if (!event.type || event.type.trim().length === 0) { errors.push({ field: 'type', message: 'Event type is required', code: 'TYPE_REQUIRED' }); } // 8. Validate title length if (event.title && event.title.length > 100) { errors.push({ field: 'title', message: 'Event title cannot exceed 100 characters', code: 'TITLE_TOO_LONG' }); } // 9. Validate location length if (event.location && event.location.length > 200) { errors.push({ field: 'location', message: 'Event location cannot exceed 200 characters', code: 'LOCATION_TOO_LONG' }); } // 10. Check for reasonable scheduling (not more than 2 years in the future) const twoYearsFromNow = new Date(); twoYearsFromNow.setFullYear(twoYearsFromNow.getFullYear() + 2); if (startTime > twoYearsFromNow) { errors.push({ field: 'startTime', message: 'Event cannot be scheduled more than 2 years in the future', code: 'START_TIME_TOO_FAR' }); } // 11. Check for business hours validation (optional warning) const startHour = startTime.getHours(); const endHour = endTime.getHours(); if (startHour < 6 || startHour > 23) { // This is a warning, not an error - we'll add it but with a different severity errors.push({ field: 'startTime', message: 'Event starts outside typical business hours (6 AM - 11 PM)', code: 'OUTSIDE_BUSINESS_HOURS' }); } return errors; } // Validate multiple events for conflicts and logical sequencing validateEventSequence(events) { const errors = []; // Sort events by start time const sortedEvents = events .map((event, index) => ({ ...event, originalIndex: index })) .sort((a, b) => new Date(a.startTime).getTime() - new Date(b.startTime).getTime()); // Check for overlapping events for (let i = 0; i < sortedEvents.length - 1; i++) { const currentEvent = sortedEvents[i]; const nextEvent = sortedEvents[i + 1]; const currentEnd = new Date(currentEvent.endTime); const nextStart = new Date(nextEvent.startTime); if (currentEnd > nextStart) { errors.push({ field: 'schedule', message: `Event "${currentEvent.title}" overlaps with "${nextEvent.title}"`, code: 'EVENTS_OVERLAP' }); } } return errors; } // Get user-friendly error messages getErrorSummary(errors) { if (errors.length === 0) return ''; const errorMessages = errors.map(error => error.message); if (errors.length === 1) { return errorMessages[0]; } return `Multiple validation errors:\n• ${errorMessages.join('\n• ')}`; } // Check if errors are warnings vs critical errors isCriticalError(error) { const warningCodes = ['OUTSIDE_BUSINESS_HOURS']; return !warningCodes.includes(error.code); } // Separate critical errors from warnings categorizeErrors(errors) { const critical = []; const warnings = []; errors.forEach(error => { if (this.isCriticalError(error)) { critical.push(error); } else { warnings.push(error); } }); return { critical, warnings }; } // Validate time format and suggest corrections validateTimeFormat(timeString) { const date = new Date(timeString); if (isNaN(date.getTime())) { return { isValid: false, suggestion: 'Please use format: YYYY-MM-DDTHH:MM (e.g., 2025-07-01T14:30)' }; } return { isValid: true }; } } exports.default = new ScheduleValidationService(); //# sourceMappingURL=scheduleValidationService.js.map