UNPKG

@uplink-protocol/calendar-controller

Version:

Flexible calendar API supporting both calendar and date-picker integrations for any JavaScript framework or library

418 lines (328 loc) 12.1 kB
# Disabled Weekdays Feature The disabled weekdays feature allows you to disable specific days of the week across all calendar views (days, months, years). This is useful for business applications, appointment scheduling, and any scenario where certain days should not be selectable. ## Overview - **Days of Week**: Represented as numbers 0-6 (0 = Sunday, 1 = Monday, ..., 6 = Saturday) - **Scope**: Applied globally across all calendar views - **Validation**: Automatically filters invalid day numbers and duplicates - **Combination**: Works seamlessly with other date constraints (min/max dates, disabled specific dates) ## Basic Usage ### Initial Configuration ```typescript import { CalendarController } from '@odyssey/date-picker'; // Disable weekends (Saturday and Sunday) const calendar = new CalendarController('#date-input', { disabledDaysOfWeek: [0, 6] // 0 = Sunday, 6 = Saturday }); // Disable specific business days const businessCalendar = new CalendarController('#business-date', { disabledDaysOfWeek: [1, 3] // Monday and Wednesday }); // Disable all weekdays (only weekends selectable) const weekendOnlyCalendar = new CalendarController('#weekend-date', { disabledDaysOfWeek: [1, 2, 3, 4, 5] // Monday through Friday }); ``` ### Dynamic Management ```typescript // Set disabled days (replaces existing) calendar.setDisabledDaysOfWeek([0, 6]); // Weekends only // Add individual days calendar.addDisabledDayOfWeek(1); // Add Monday calendar.addDisabledDayOfWeek(5); // Add Friday // Remove individual days calendar.removeDisabledDayOfWeek(0); // Remove Sunday // Get current disabled days const disabledDays = calendar.getDisabledDaysOfWeek(); console.log('Disabled days:', disabledDays); // [1, 5, 6] ``` ## API Reference ### CalendarOptions ```typescript interface CalendarOptions { disabledDaysOfWeek?: number[]; // Array of day numbers (0-6) // ... other options } ``` ### CalendarController Methods ```typescript class CalendarController { // Set disabled days of week (replaces existing array) setDisabledDaysOfWeek(days: number[]): number[]; // Add a single day to disabled days addDisabledDayOfWeek(day: number): number[]; // Remove a single day from disabled days removeDisabledDayOfWeek(day: number): number[]; // Get current disabled days of week getDisabledDaysOfWeek(): number[]; } ``` ### Day Number Reference | Day | Number | |-----|--------| | Sunday | 0 | | Monday | 1 | | Tuesday | 2 | | Wednesday | 3 | | Thursday | 4 | | Friday | 5 | | Saturday | 6 | ## Common Use Cases ### 1. Business Hours (Weekdays Only) ```typescript const businessCalendar = new CalendarController('#appointment-date', { disabledDaysOfWeek: [0, 6], // Disable weekends minDate: new Date(), // Only future dates onDateSelect: (date) => { console.log('Business day selected:', date); } }); ``` ### 2. Service Availability ```typescript // Service available Tuesday, Thursday, Saturday only const serviceCalendar = new CalendarController('#service-date', { disabledDaysOfWeek: [0, 1, 3, 5], // Disable Sun, Mon, Wed, Fri onDateSelect: (date) => { scheduleService(date); } }); ``` ### 3. Maintenance Windows ```typescript // No deployments on Fridays and weekends const deploymentCalendar = new CalendarController('#deployment-date', { disabledDaysOfWeek: [0, 5, 6], // Disable Fri, Sat, Sun disabledDates: getHolidayDates(), // Also disable holidays }); ``` ### 4. Educational Calendar ```typescript // School days only (no weekends) const schoolCalendar = new CalendarController('#class-date', { disabledDaysOfWeek: [0, 6], // No weekends minDate: new Date(2024, 8, 1), // School year start maxDate: new Date(2025, 5, 30), // School year end disabledDates: getSchoolHolidays() }); ``` ### 5. Dynamic Business Rules ```typescript class BusinessRuleManager { constructor(calendarSelector) { this.calendar = new CalendarController(calendarSelector, { disabledDaysOfWeek: [] }); } // Apply different rules based on business type applyBusinessHours(businessType) { switch (businessType) { case 'retail': this.calendar.setDisabledDaysOfWeek([]); // Open all days break; case 'office': this.calendar.setDisabledDaysOfWeek([0, 6]); // Weekdays only break; case 'restaurant': this.calendar.setDisabledDaysOfWeek([1]); // Closed Mondays break; case 'medical': this.calendar.setDisabledDaysOfWeek([0]); // Closed Sundays break; } } // Seasonal adjustments applySummerSchedule() { this.calendar.addDisabledDayOfWeek(5); // Close Fridays in summer } applyWinterSchedule() { this.calendar.removeDisabledDayOfWeek(5); // Reopen Fridays } } ``` ## Advanced Examples ### Combining with Other Constraints ```typescript const appointmentCalendar = new CalendarController('#appointment', { // Date range constraints minDate: new Date(), maxDate: new Date(2025, 11, 31), // Weekday constraints disabledDaysOfWeek: [0, 6], // No weekends // Specific date constraints disabledDates: [ new Date(2024, 11, 25), // Christmas new Date(2024, 11, 26), // Boxing Day new Date(2025, 0, 1), // New Year ...getCompanyHolidays() ], // Callback when valid date selected onDateSelect: (date) => { if (isBusinessDay(date)) { bookAppointment(date); } } }); ``` ### Interactive Configuration UI ```typescript class CalendarConfigUI { constructor() { this.calendar = new CalendarController('#configurable-calendar'); this.setupUI(); } setupUI() { // Create checkboxes for each day const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; const container = document.getElementById('day-checkboxes'); days.forEach((dayName, index) => { const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = `day-${index}`; checkbox.value = index; checkbox.addEventListener('change', () => this.updateDisabledDays()); const label = document.createElement('label'); label.htmlFor = `day-${index}`; label.textContent = dayName; container.appendChild(checkbox); container.appendChild(label); }); } updateDisabledDays() { const checkboxes = document.querySelectorAll('#day-checkboxes input:checked'); const disabledDays = Array.from(checkboxes).map(cb => parseInt(cb.value)); this.calendar.setDisabledDaysOfWeek(disabledDays); this.updateStatusDisplay(disabledDays); } updateStatusDisplay(disabledDays) { const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; const disabledNames = disabledDays.map(day => dayNames[day]); document.getElementById('status').textContent = disabledNames.length ? `Disabled: ${disabledNames.join(', ')}` : 'All days enabled'; } // Preset configurations presetWeekends() { this.setCheckboxes([0, 6]); this.updateDisabledDays(); } presetWeekdays() { this.setCheckboxes([1, 2, 3, 4, 5]); this.updateDisabledDays(); } clearAll() { this.setCheckboxes([]); this.updateDisabledDays(); } setCheckboxes(days) { document.querySelectorAll('#day-checkboxes input').forEach(cb => { cb.checked = days.includes(parseInt(cb.value)); }); } } ``` ## Validation and Error Handling The disabled weekdays feature includes automatic validation: ```typescript // Invalid day numbers are filtered out calendar.setDisabledDaysOfWeek([0, 7, -1, 6, 15]); // Result: [0, 6] (only valid days 0-6 are kept) // Duplicates are automatically removed calendar.setDisabledDaysOfWeek([1, 1, 2, 2, 3]); // Result: [1, 2, 3] // Adding existing day has no effect calendar.setDisabledDaysOfWeek([1, 2]); calendar.addDisabledDayOfWeek(1); // No change // Result: [1, 2] // Removing non-existent day has no effect calendar.removeDisabledDayOfWeek(5); // No change if 5 wasn't disabled ``` ## Testing The feature includes comprehensive test coverage: - **Validation Tests**: Ensure only valid day numbers (0-6) are accepted - **Management Tests**: Verify add/remove operations work correctly - **Integration Tests**: Test interaction with other date constraints - **Calendar Generation Tests**: Verify disabled days appear correctly in calendar views - **Edge Case Tests**: Handle empty arrays, invalid inputs, and boundary conditions Run the tests: ```bash npm test ``` ## Browser Support The disabled weekdays feature works in all modern browsers that support: - ES6 Arrays and Array methods - Date object and `getDay()` method - Standard DOM events ## Performance Considerations - **Efficient Filtering**: Day validation uses Set operations for O(1) lookups - **Minimal Recalculation**: Calendar only regenerates when disabled days change - **Memory Efficient**: Stores only the day numbers, not full date objects - **Batch Operations**: Use `setDisabledDaysOfWeek()` for multiple changes instead of multiple `addDisabledDayOfWeek()` calls ## Migration Guide If upgrading from a version without disabled weekdays support: ### From Custom Implementation ```typescript // Before (custom implementation) const isWeekend = (date) => { const day = date.getDay(); return day === 0 || day === 6; }; const calendar = new CalendarController('#date-input', { customValidation: (date) => !isWeekend(date) }); // After (built-in feature) const calendar = new CalendarController('#date-input', { disabledDaysOfWeek: [0, 6] }); ``` ### Adding to Existing Calendar ```typescript // Existing calendar instance const existingCalendar = new CalendarController('#date-input', { minDate: new Date(), maxDate: new Date(2025, 11, 31) }); // Add disabled weekdays existingCalendar.setDisabledDaysOfWeek([0, 6]); ``` ## Best Practices 1. **Use Meaningful Constants**: ```typescript const WEEKENDS = [0, 6]; const WEEKDAYS = [1, 2, 3, 4, 5]; const BUSINESS_DAYS = [1, 2, 3, 4, 5]; calendar.setDisabledDaysOfWeek(WEEKENDS); ``` 2. **Provide User Feedback**: ```typescript calendar.setDisabledDaysOfWeek([0, 6]); showNotification('Weekends are now disabled'); ``` 3. **Document Business Rules**: ```typescript // Business rule: No appointments on weekends or Fridays // Fridays are reserved for internal meetings calendar.setDisabledDaysOfWeek([0, 5, 6]); ``` 4. **Combine with Validation**: ```typescript calendar.setDisabledDaysOfWeek([0, 6]); calendar.onDateSelect = (date) => { if (isHoliday(date)) { showError('Selected date is a holiday'); return; } processSelection(date); }; ``` 5. **Save User Preferences**: ```typescript const savedDisabledDays = localStorage.getItem('disabledDays'); if (savedDisabledDays) { calendar.setDisabledDaysOfWeek(JSON.parse(savedDisabledDays)); } // Save when changed calendar.onDisabledDaysChange = (days) => { localStorage.setItem('disabledDays', JSON.stringify(days)); }; ```