@uplink-protocol/calendar-controller
Version:
Flexible calendar and time picker API supporting both calendar, date-picker, and time-picker integrations for any JavaScript framework or library
663 lines (568 loc) • 23.5 kB
JavaScript
/**
* Advanced Date Controller Examples
*
* This file demonstrates advanced features, edge cases, and complex scenarios
* Run with: node advanced-date-examples.js
*/
const { CalendarController } = require('../../dist/index.js');
console.log('📅 Advanced Date Controller Examples\n');
console.log('====================================\n');
// ========================================
// 1. Complex Date Constraints & Business Rules
// ========================================
console.log('1. 🏢 Complex Date Constraints & Business Rules');
console.log('-----------------------------------------------');
const businessCalendar = CalendarController({
firstDayOfWeek: 1, // Monday start
isRangeSelection: false,
hideOtherMonthDays: false
});
// Business rules: No weekends, no holidays, no first week of each quarter
const holidays2025 = [
new Date(2025, 0, 1), // New Year's Day
new Date(2025, 0, 20), // MLK Day
new Date(2025, 1, 17), // Presidents Day
new Date(2025, 4, 26), // Memorial Day
new Date(2025, 6, 4), // Independence Day
new Date(2025, 8, 1), // Labor Day
new Date(2025, 9, 13), // Columbus Day
new Date(2025, 10, 11), // Veterans Day
new Date(2025, 10, 27), // Thanksgiving
new Date(2025, 11, 25) // Christmas
];
// Disable weekends (Saturday=6, Sunday=0)
businessCalendar.methods.setDisabledDaysOfWeek([0, 6]);
// Disable holidays
businessCalendar.methods.setDisabledDates(holidays2025);
// Set business constraints: Only allow dates 30 days in future, up to 6 months ahead
const today = new Date();
const minBusinessDate = new Date(today);
minBusinessDate.setDate(today.getDate() + 30);
const maxBusinessDate = new Date(today);
maxBusinessDate.setMonth(today.getMonth() + 6);
businessCalendar.methods.setMinDate(minBusinessDate);
businessCalendar.methods.setMaxDate(maxBusinessDate);
console.log('✅ Business Calendar System:');
console.log(` - Min date: ${minBusinessDate.toDateString()}`);
console.log(` - Max date: ${maxBusinessDate.toDateString()}`);
console.log(` - Disabled holidays: ${holidays2025.length} dates`);
console.log(' - Weekends disabled');
// Test various business dates
const testBusinessDates = [
{ date: new Date(2025, 6, 4), label: 'Independence Day (Holiday)' },
{ date: new Date(2025, 6, 5), label: 'Saturday (Weekend)' },
{ date: new Date(2025, 6, 7), label: 'Monday (Business day)' },
{ date: new Date(2025, 11, 15), label: 'Future Monday' },
{ date: new Date(2025, 5, 28), label: 'Next week Saturday' }
];
testBusinessDates.forEach(test => {
const isDisabled = businessCalendar.methods.isDateDisabled(test.date);
console.log(` ${test.label}: ${isDisabled ? '❌ Blocked' : '✅ Available'}`);
});
console.log('');
// ========================================
// 2. Multi-locale & International Support
// ========================================
console.log('2. 🌍 Multi-locale & International Support');
console.log('------------------------------------------');
const locales = [
{ code: 'en-US', name: 'English (US)', firstDay: 0 },
{ code: 'en-GB', name: 'English (UK)', firstDay: 1 },
{ code: 'fr-FR', name: 'French (France)', firstDay: 1 },
{ code: 'de-DE', name: 'German (Germany)', firstDay: 1 },
{ code: 'ja-JP', name: 'Japanese (Japan)', firstDay: 0 },
{ code: 'ar-SA', name: 'Arabic (Saudi Arabia)', firstDay: 0 },
{ code: 'zh-CN', name: 'Chinese (China)', firstDay: 1 },
{ code: 'es-ES', name: 'Spanish (Spain)', firstDay: 1 }
];
const testDate = new Date(2025, 5, 26); // June 26, 2025
console.log('✅ Same date across different locales:');
locales.forEach(locale => {
const calendar = CalendarController({
locale: locale.code,
firstDayOfWeek: locale.firstDay
});
calendar.methods.selectDate(testDate);
// Get month names and weekdays
const monthNames = calendar.methods.getMonthNames();
const weekdays = calendar.methods.getWeekdayNames(true);
const formatted = calendar.methods.formatDate(testDate);
console.log(` ${locale.name}:`);
console.log(` Date: ${formatted}`);
console.log(` Month: ${monthNames[testDate.getMonth()]}`);
console.log(` First weekday: ${weekdays[0]}`);
});
console.log('');
// ========================================
// 3. Date Range Selection & Booking Systems
// ========================================
console.log('3. 📋 Date Range Selection & Booking Systems');
console.log('--------------------------------------------');
const hotelBooking = CalendarController({
isRangeSelection: true,
firstDayOfWeek: 1,
minDate: new Date(2025, 5, 26), // Today onwards
maxDate: new Date(2025, 11, 31) // End of year
});
// Simulate existing bookings (blocked date ranges)
const existingBookings = [
{ start: new Date(2025, 6, 10), end: new Date(2025, 6, 15), guest: 'Smith Family' },
{ start: new Date(2025, 6, 20), end: new Date(2025, 6, 25), guest: 'Jones Group' },
{ start: new Date(2025, 7, 5), end: new Date(2025, 7, 12), guest: 'Wilson Wedding' }
];
// Create blocked dates array from existing bookings
const blockedDates = [];
existingBookings.forEach(booking => {
const current = new Date(booking.start);
while (current <= booking.end) {
blockedDates.push(new Date(current));
current.setDate(current.getDate() + 1);
}
});
hotelBooking.methods.setDisabledDates(blockedDates);
console.log('✅ Hotel Booking System:');
console.log(' Existing reservations:');
existingBookings.forEach((booking, i) => {
console.log(` ${i + 1}. ${booking.guest}: ${booking.start.toDateString()} - ${booking.end.toDateString()}`);
});
// Test new booking requests
const newBookingRequests = [
{ start: new Date(2025, 6, 5), end: new Date(2025, 6, 9), label: 'July 5-9' },
{ start: new Date(2025, 6, 12), end: new Date(2025, 6, 18), label: 'July 12-18 (Overlaps)' },
{ start: new Date(2025, 7, 15), end: new Date(2025, 7, 20), label: 'August 15-20' }
];
console.log('\n Testing new booking requests:');
newBookingRequests.forEach(request => {
const hasConflict = blockedDates.some(blocked =>
blocked >= request.start && blocked <= request.end
);
console.log(` ${request.label}: ${hasConflict ? '❌ Conflict' : '✅ Available'}`);
});
console.log('');
// ========================================
// 4. Dynamic Calendar View Navigation
// ========================================
console.log('4. 🗓️ Dynamic Calendar View Navigation');
console.log('--------------------------------------');
const viewNavigator = CalendarController({
firstDayOfWeek: 1,
yearRangeSize: 12
});
// Navigate through different views and time periods
console.log('✅ Calendar view navigation:');
// Start with current month
console.log(` Current month: ${viewNavigator.bindings.monthName.current} ${viewNavigator.bindings.currentYear.current}`);
// Navigate to specific month/year
viewNavigator.methods.selectMonth(11, 2025); // December 2025
console.log(` Navigate to: ${viewNavigator.bindings.monthName.current} ${viewNavigator.bindings.currentYear.current}`);
// Generate different view types
const monthView = viewNavigator.methods.generateMonthView();
console.log(` Month view: ${monthView.weeks.length} weeks, ${monthView.weekdays.length} weekdays`);
const monthsData = viewNavigator.methods.generateCalendarMonths();
console.log(` Year view: ${monthsData.length} months for ${viewNavigator.bindings.currentYear.current}`);
const yearsData = viewNavigator.methods.generateCalendarYears();
console.log(` Decade view: ${yearsData.length} years (${yearsData[0].year}-${yearsData[yearsData.length-1].year})`);
// Year range navigation
console.log('\n Year range navigation:');
const currentRange = viewNavigator.methods.getCurrentYearRange();
console.log(` Current decade: ${currentRange.startYear}-${currentRange.endYear}`);
viewNavigator.methods.goToNextYearRange();
const nextRange = viewNavigator.methods.getCurrentYearRange();
console.log(` Next decade: ${nextRange.startYear}-${nextRange.endYear}`);
viewNavigator.methods.goToPreviousYearRange();
console.log(' Returned to previous decade');
console.log('');
// ========================================
// 5. Accessibility & Keyboard Navigation
// ========================================
console.log('5. ♿ Accessibility & Keyboard Navigation');
console.log('----------------------------------------');
const accessibleCalendar = CalendarController({
firstDayOfWeek: 1
});
// Set focus to a specific date
const focusDate = new Date(2025, 5, 26);
accessibleCalendar.methods.setFocusedDate(focusDate);
console.log('✅ Accessibility features:');
console.log(` Focused date: ${accessibleCalendar.bindings.focusedDate.current?.toDateString()}`);
// Test accessible labels
const testDates = [
new Date(2025, 5, 26), // Today
new Date(2025, 5, 25), // Yesterday
new Date(2025, 5, 27), // Tomorrow
new Date(2025, 6, 4), // Independence Day
];
console.log('\n Accessible date labels:');
testDates.forEach(date => {
const label = accessibleCalendar.methods.getAccessibleDateLabel(date);
const stateDesc = accessibleCalendar.methods.getDateStateDescription(date);
console.log(` ${date.toDateString()}`);
console.log(` Label: ${label}`);
console.log(` State: ${stateDesc}`);
});
// Simulate keyboard navigation
console.log('\n Keyboard navigation simulation:');
const keyboardActions = [
'Focus right (next day)',
'Focus down (next week)',
'Focus to month start',
'Focus to month end',
'Focus to next month',
'Select focused date'
];
keyboardActions.forEach((action, i) => {
switch (i) {
case 0:
accessibleCalendar.methods.moveFocusRight();
break;
case 1:
accessibleCalendar.methods.moveFocusDown();
break;
case 2:
accessibleCalendar.methods.moveFocusToStartOfMonth();
break;
case 3:
accessibleCalendar.methods.moveFocusToEndOfMonth();
break;
case 4:
accessibleCalendar.methods.moveFocusToNextMonth();
break;
case 5:
accessibleCalendar.methods.selectFocusedDate();
break;
}
console.log(` ${i + 1}. ${action}`);
if (accessibleCalendar.bindings.focusedDate.current) {
console.log(` Focus: ${accessibleCalendar.bindings.focusedDate.current.toDateString()}`);
}
if (accessibleCalendar.bindings.selectedDate.current) {
console.log(` Selected: ${accessibleCalendar.bindings.selectedDate.current.toDateString()}`);
}
});
console.log('');
// ========================================
// 6. Event-Driven Calendar Updates
// ========================================
console.log('6. 🎭 Event-Driven Calendar Updates');
console.log('-----------------------------------');
const eventCalendar = CalendarController({
firstDayOfWeek: 1
});
let eventLog = [];
// Subscribe to all calendar events
console.log('✅ Setting up event subscriptions:');
if (eventCalendar.events.dateSelected) {
eventCalendar.events.dateSelected.subscribe((date) => {
eventLog.push(`Date selected: ${date.toDateString()}`);
console.log(` 📅 ${eventLog[eventLog.length - 1]}`);
});
}
if (eventCalendar.events.monthChanged) {
eventCalendar.events.monthChanged.subscribe((month) => {
eventLog.push(`Month changed: ${month}`);
console.log(` 📆 ${eventLog[eventLog.length - 1]}`);
});
}
if (eventCalendar.events.yearChanged) {
eventCalendar.events.yearChanged.subscribe((year) => {
eventLog.push(`Year changed: ${year}`);
console.log(` 🗓️ ${eventLog[eventLog.length - 1]}`);
});
}
if (eventCalendar.events.viewChanged) {
eventCalendar.events.viewChanged.subscribe((view) => {
eventLog.push(`View changed: ${view.month + 1}/${view.year}`);
console.log(` 👁️ ${eventLog[eventLog.length - 1]}`);
});
}
// Trigger various events
console.log('\n Triggering calendar events:');
eventCalendar.methods.selectDate(new Date(2025, 7, 15));
eventCalendar.methods.goToNextMonth();
eventCalendar.methods.goToNextYear();
eventCalendar.methods.selectMonth(2, 2026); // March 2026
console.log(`\n Total events fired: ${eventLog.length}`);
console.log('');
// ========================================
// 7. Calendar Data Generation & Analysis
// ========================================
console.log('7. 📊 Calendar Data Generation & Analysis');
console.log('-----------------------------------------');
const dataCalendar = CalendarController({
firstDayOfWeek: 1,
hideOtherMonthDays: false
});
// Navigate to specific month for analysis
dataCalendar.methods.goToMonth(6, 2025); // July 2025
console.log('✅ Calendar data analysis for July 2025:');
// Generate calendar days with detailed analysis
const calendarDays = dataCalendar.methods.generateCalendarDays();
const currentMonthDays = calendarDays.filter(day => day.isCurrentMonth);
const otherMonthDays = calendarDays.filter(day => !day.isCurrentMonth);
const weekends = calendarDays.filter(day => day.dayOfWeek === 0 || day.dayOfWeek === 6);
console.log(` Total calendar cells: ${calendarDays.length}`);
console.log(` Current month days: ${currentMonthDays.length}`);
console.log(` Other month days: ${otherMonthDays.length}`);
console.log(` Weekend days: ${weekends.length}`);
// Week analysis
const monthView = dataCalendar.methods.generateMonthView();
console.log(`\n Weekly breakdown:`);
monthView.weeks.forEach((week, i) => {
const weekDays = week.days.filter(day => day.isCurrentMonth);
const weekNumber = dataCalendar.methods.getWeekNumber(weekDays[0]?.date || new Date());
console.log(` Week ${i + 1} (ISO week ${weekNumber}): ${weekDays.length} days in month`);
});
// Month analysis across the year
console.log('\n Year overview:');
const yearMonths = dataCalendar.methods.generateCalendarMonths();
yearMonths.forEach(month => {
const monthName = dataCalendar.methods.getMonthNames()[month.month];
console.log(` ${monthName}: ${month.isCurrentMonth ? 'Current' : 'Available'}, ${month.isDisabled ? 'Disabled' : 'Enabled'}`);
});
console.log('');
// ========================================
// 8. Performance Testing & Optimization
// ========================================
console.log('8. 📈 Performance Testing & Optimization');
console.log('----------------------------------------');
const perfCalendar = CalendarController({
firstDayOfWeek: 1
});
// Test performance of various operations
const performanceTests = [
{
name: 'Date Selection',
test: () => {
const start = performance.now();
for (let i = 0; i < 1000; i++) {
const randomDate = new Date(2025, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1);
perfCalendar.methods.selectDate(randomDate);
}
return performance.now() - start;
}
},
{
name: 'Calendar Generation',
test: () => {
const start = performance.now();
for (let i = 0; i < 100; i++) {
perfCalendar.methods.generateCalendarDays();
perfCalendar.methods.generateCalendarMonths();
perfCalendar.methods.generateCalendarYears();
}
return performance.now() - start;
}
},
{
name: 'Navigation Operations',
test: () => {
const start = performance.now();
for (let i = 0; i < 500; i++) {
perfCalendar.methods.goToNextMonth();
perfCalendar.methods.goToPreviousMonth();
perfCalendar.methods.goToNextYear();
perfCalendar.methods.goToPreviousYear();
}
return performance.now() - start;
}
},
{
name: 'Date Validation',
test: () => {
const testDates = [];
for (let i = 0; i < 365; i++) {
const date = new Date(2025, 0, 1);
date.setDate(date.getDate() + i);
testDates.push(date);
}
const start = performance.now();
testDates.forEach(date => {
perfCalendar.methods.isDateDisabled(date);
perfCalendar.methods.isToday(date);
});
return performance.now() - start;
}
}
];
console.log('✅ Performance test results:');
performanceTests.forEach(test => {
const duration = test.test();
console.log(` ${test.name}: ${duration.toFixed(2)}ms`);
});
console.log('');
// ========================================
// 9. Edge Cases & Error Handling
// ========================================
console.log('9. 🚨 Edge Cases & Error Handling');
console.log('----------------------------------');
const robustCalendar = CalendarController({
firstDayOfWeek: 1
});
const edgeCases = [
{
name: 'Leap year handling',
test: () => {
// Test February 29th in leap years and non-leap years
const leapYear = new Date(2024, 1, 29); // Feb 29, 2024 (leap year)
const nonLeapYear = new Date(2025, 1, 29); // Feb 29, 2025 (not leap year - invalid)
robustCalendar.methods.selectDate(leapYear);
const leapResult = robustCalendar.bindings.selectedDate.current?.toDateString() || 'Failed';
try {
robustCalendar.methods.selectDate(nonLeapYear);
const nonLeapResult = robustCalendar.bindings.selectedDate.current?.toDateString() || 'Failed';
return `Leap: ${leapResult}, Non-leap: ${nonLeapResult}`;
} catch (error) {
return `Leap: ${leapResult}, Non-leap: Properly rejected`;
}
}
},
{
name: 'Year boundary navigation',
test: () => {
robustCalendar.methods.goToMonth(11, 2025); // December 2025
const dec2025 = `${robustCalendar.bindings.monthName.current} ${robustCalendar.bindings.currentYear.current}`;
robustCalendar.methods.goToNextMonth(); // Should go to January 2026
const jan2026 = `${robustCalendar.bindings.monthName.current} ${robustCalendar.bindings.currentYear.current}`;
return `${dec2025} → ${jan2026}`;
}
},
{
name: 'Invalid date constraints',
test: () => {
try {
// Try to set min date after max date
robustCalendar.methods.setMinDate(new Date(2025, 11, 31));
robustCalendar.methods.setMaxDate(new Date(2025, 0, 1));
return 'Invalid constraints accepted (potential issue)';
} catch (error) {
return 'Invalid constraints properly rejected';
}
}
},
{
name: 'Extreme date values',
test: () => {
try {
const extremeDate = new Date(2100, 0, 1);
robustCalendar.methods.selectDate(extremeDate);
return `Extreme future date: ${robustCalendar.bindings.selectedDate.current?.getFullYear() || 'Failed'}`;
} catch (error) {
return 'Extreme date properly handled';
}
}
}
];
console.log('✅ Edge case testing:');
edgeCases.forEach(testCase => {
try {
const result = testCase.test();
console.log(` ${testCase.name}: ✅ ${result}`);
} catch (error) {
console.log(` ${testCase.name}: ❌ ${error.message}`);
}
});
console.log('');
// ========================================
// 10. Integration with External Data Sources
// ========================================
console.log('10. 🔗 Integration with External Data Sources');
console.log('----------------------------------------------');
const integrationCalendar = CalendarController({
firstDayOfWeek: 1,
isRangeSelection: true
});
// Simulate external calendar events/appointments
const externalEvents = [
{
id: 'evt1',
title: 'Team Standup',
date: new Date(2025, 5, 27),
type: 'recurring',
priority: 'normal'
},
{
id: 'evt2',
title: 'Client Presentation',
date: new Date(2025, 5, 30),
type: 'meeting',
priority: 'high'
},
{
id: 'evt3',
title: 'Project Deadline',
date: new Date(2025, 6, 15),
type: 'deadline',
priority: 'critical'
},
{
id: 'evt4',
title: 'Team Building',
date: new Date(2025, 6, 20),
type: 'event',
priority: 'low'
}
];
// Integrate external events with calendar
const eventDates = externalEvents.map(event => event.date);
console.log('✅ External calendar integration:');
console.log(' External events:');
externalEvents.forEach((event, i) => {
console.log(` ${i + 1}. ${event.title} (${event.date.toDateString()}) - ${event.priority} priority`);
});
// Find available dates for new meetings (avoiding existing events)
const findAvailableDates = (startDate, daysToCheck, excludeDates) => {
const available = [];
const current = new Date(startDate);
for (let i = 0; i < daysToCheck; i++) {
const isWeekend = current.getDay() === 0 || current.getDay() === 6;
const hasEvent = excludeDates.some(excludeDate =>
excludeDate.toDateString() === current.toDateString()
);
if (!isWeekend && !hasEvent) {
available.push(new Date(current));
}
current.setDate(current.getDate() + 1);
}
return available.slice(0, 5); // Return first 5 available dates
};
const availableDates = findAvailableDates(new Date(2025, 5, 26), 30, eventDates);
console.log('\n Available dates for new meetings (next 30 days):');
availableDates.forEach((date, i) => {
console.log(` ${i + 1}. ${date.toDateString()}`);
});
// Event density analysis
const eventsByMonth = {};
externalEvents.forEach(event => {
const monthKey = `${event.date.getFullYear()}-${event.date.getMonth()}`;
eventsByMonth[monthKey] = (eventsByMonth[monthKey] || 0) + 1;
});
console.log('\n Event density by month:');
Object.entries(eventsByMonth).forEach(([monthKey, count]) => {
const [year, month] = monthKey.split('-');
const monthName = integrationCalendar.methods.getMonthNames()[parseInt(month)];
console.log(` ${monthName} ${year}: ${count} events`);
});
console.log('');
console.log('🎯 Advanced Date Examples Complete!');
console.log('===================================');
console.log('');
console.log('Advanced capabilities demonstrated:');
console.log('• 🏢 Complex business rules & constraints');
console.log('• 🌍 Multi-locale & internationalization');
console.log('• 📋 Date range selection & booking systems');
console.log('• 🗓️ Dynamic view navigation & generation');
console.log('• ♿ Accessibility & keyboard navigation');
console.log('• 🎭 Event-driven reactive updates');
console.log('• 📊 Calendar data analysis');
console.log('• 📈 Performance optimization');
console.log('• 🚨 Robust error handling');
console.log('• 🔗 External system integration');
console.log('');
console.log('These examples show how the Calendar Controller can handle:');
console.log('• Enterprise scheduling applications');
console.log('• Hotel/booking reservation systems');
console.log('• Multi-language calendar interfaces');
console.log('• Accessibility-compliant date pickers');
console.log('• High-performance calendar widgets');
console.log('• Complex business rule enforcement');
console.log('• Integration with external calendar systems');