Skip to main content

Calendar Components

The Calendar Components provide powerful calendar functionality for scheduling, event management, and time-based data visualization. The system includes both legacy (V1) and enhanced (V2) calendar implementations with different feature sets and capabilities.

Overview

This document covers all calendar-related components that provide scheduling, event display, and calendar navigation within the WorkPayCore Frontend application. The calendar system is built on react-big-calendar with custom WorkPay-specific enhancements.

Components Overview

Calendar Implementations

Integration Components


WPCalendar (V1)

The legacy calendar implementation providing basic calendar functionality with event display and navigation.

Component Location

import WPCalendar from 'components/Calendar';

Props

PropTypeRequiredDefaultDescription
eventsobject-Calendar events data
loadingboolean-Loading state indicator
viewsarray-['month']Available calendar views
viewDateDate-new Date()Initial calendar date
onSelectEventfunction--Event selection handler
tooltipAccessorstring-''Tooltip data accessor
onShowMorefunction--Show more events handler
eventPropGetterfunction--Event styling function
showAllEventsboolean-falseShow all events flag
componentsobject--Custom component overrides
showTodayboolean-trueShow today button
showViewsboolean-trueShow view selector
pagestring--Page context for styling
colorDescarray--Color legend descriptions

TypeScript Interface

interface WPCalendarV1Props {
events: Record<string, any>;
loading: boolean;
views?: Array<'month' | 'week' | 'day'>;
viewDate?: Date;
onSelectEvent?: (event: any) => void;
tooltipAccessor?: string;
onShowMore?: (events: any[]) => void;
eventPropGetter?: (
event: any,
start: Date,
end: Date,
isSelected: boolean,
) => {
className?: string;
style?: React.CSSProperties;
};
showAllEvents?: boolean;
components?: {
event?: React.ComponentType&lt;any&gt;;
[key: string]: any;
};
showToday?: boolean;
showViews?: boolean;
page?: string;
colorDesc?: Array<{
name: string;
bgColor: string;
}>;
}

Features

Basic Calendar Views

  • Month View: Monthly calendar layout with events
  • Week View: Weekly calendar layout (if enabled)
  • Day View: Daily calendar layout (if enabled)

Event Display

  • Custom event rendering
  • Event tooltips
  • Event selection handling
  • Show more events popup
  • Previous/Next navigation
  • Today button
  • View switching
  • Date navigation

Usage Examples

Basic Calendar Usage

import WPCalendar from 'components/Calendar';

function BasicCalendar() {
const [events, setEvents] = useState([]);
const [loading, setLoading] = useState(false);

const handleEventSelect = event => {
console.log('Selected event:', event);
};

return (
<WPCalendar
events={events}
loading={loading}
onSelectEvent={handleEventSelect}
views={['month']}
showToday={true}
showViews={false}
/>
);
}

Calendar with Custom Event Styling

import WPCalendar from 'components/Calendar';

function StyledCalendar() {
const eventPropGetter = (event, start, end, isSelected) => {
let backgroundColor = '#3174ad';

if (event.type === 'leave') {
backgroundColor = '#f56565';
} else if (event.type === 'meeting') {
backgroundColor = '#38a169';
}

return {
style: {
backgroundColor,
borderRadius: '5px',
opacity: 0.8,
color: 'white',
border: '0px',
display: 'block',
},
};
};

return (
<WPCalendar
events={events}
loading={loading}
eventPropGetter={eventPropGetter}
views={['month', 'week']}
/>
);
}

Calendar with Color Legend

import WPCalendar from 'components/Calendar';

function CalendarWithLegend() {
const colorDescriptions = [
{ name: 'Approved Leave', bgColor: '#38a169' },
{ name: 'Pending Leave', bgColor: '#ecc94b' },
{ name: 'Rejected Leave', bgColor: '#f56565' },
];

return (
<WPCalendar
events={events}
loading={loading}
colorDesc={colorDescriptions}
page='leave-scheduling'
/>
);
}

WPCalendar (V2)

The enhanced calendar implementation with advanced filtering, improved navigation, and event management capabilities.

Component Location

import WPCalendar from 'components/CalendarV2';

Props

PropTypeRequiredDefaultDescription
eventsEvent[]-Calendar events array
loadingboolean-Loading state indicator
viewsarray-Available calendar views
viewDateDate-new Date()Initial calendar date
eventPropGetterfunction-Event styling function
componentsobject-Custom component overrides
handleResetFiltersfunction-Reset filters handler
searchTextstring-Search text value
setSearchTextfunction-Search text setter
LeaveStatusOptionarray-Leave status options
leaveStatusstring-Current leave status
handleLeaveStatusFilterfunction-Status filter handler
handleChangeDatefunction-Date change handler
setFiltersfunction-Filters setter
filtersobject-Current filters

TypeScript Interface

interface Event {
type: string;
title: string;
start: Date;
end: Date;
status: string;
data: {
profile_picture?: string;
leave_type_name?: string;
[key: string]: any;
};
}

interface WPCalendarV2Props {
events: Event[];
loading: boolean;
views: Array<'month' | 'week' | 'day'>;
viewDate?: Date;
eventPropGetter: (
event: any,
start: Date,
end: Date,
isSelected: boolean,
) => {
className?: string;
style?: React.CSSProperties;
};
components: any;
handleResetFilters: () => void;
searchText: string;
setSearchText: (text: string) => void;
LeaveStatusOption: Array<{
value: string;
label: string;
}>;
leaveStatus: string;
handleLeaveStatusFilter: (event: any) => void;
handleChangeDate: (date: Date) => void;
setFilters: (filters: Record<string, any>) => void;
filters: Record<string, any>;
}

Enhanced Features

Advanced Filtering

  • Search Functionality: Text-based event search
  • Status Filtering: Filter by leave/event status
  • Date Range Filtering: Automatic month/year filtering
  • Reset Filters: Clear all applied filters

Enhanced Navigation

  • Range Change Detection: Automatic filter updates on navigation
  • View State Management: Persistent view preferences
  • Today Highlighting: Current date highlighting

Event Management

  • Event Popup Modal: Detailed event information
  • Show More Events: Handle multiple events per day
  • Event Selection: Enhanced event interaction
  • Status-based Styling: Dynamic event colors

Improved UI/UX

  • Responsive Design: Better mobile experience
  • Custom Formatting: Enhanced date/time formatting
  • Loading States: Improved loading indicators
  • Accessibility: Better keyboard navigation

Usage Examples

Complete Calendar V2 Implementation

import WPCalendar from 'components/CalendarV2';

function AdvancedCalendar() {
const [events, setEvents] = useState([]);
const [loading, setLoading] = useState(false);
const [searchText, setSearchText] = useState('');
const [leaveStatus, setLeaveStatus] = useState('');
const [filters, setFilters] = useState({});

const LeaveStatusOptions = [
{ value: 'APPROVED', label: 'Approved' },
{ value: 'PENDING', label: 'Pending' },
{ value: 'REJECTED', label: 'Rejected' },
];

const handleResetFilters = () => {
setSearchText('');
setLeaveStatus('');
setFilters({});
};

const handleLeaveStatusFilter = selectedOption => {
setLeaveStatus(selectedOption.value);
};

const handleChangeDate = date => {
setFilters({
...filters,
selectedDate: date,
});
};

const eventPropGetter = (event, start, end, isSelected) => {
let backgroundColor = '#3174ad';

switch (event.status) {
case 'APPROVED':
backgroundColor = '#38a169';
break;
case 'PENDING':
backgroundColor = '#ecc94b';
break;
case 'REJECTED':
backgroundColor = '#f56565';
break;
default:
backgroundColor = '#3174ad';
}

return {
style: {
backgroundColor,
borderRadius: '8px',
opacity: 0.9,
color: 'white',
border: 'none',
fontSize: '12px',
padding: '2px 6px',
},
};
};

return (
<WPCalendar
events={events}
loading={loading}
views={['month', 'week', 'day']}
viewDate={new Date()}
eventPropGetter={eventPropGetter}
components={{}}
handleResetFilters={handleResetFilters}
searchText={searchText}
setSearchText={setSearchText}
LeaveStatusOption={LeaveStatusOptions}
leaveStatus={leaveStatus}
handleLeaveStatusFilter={handleLeaveStatusFilter}
handleChangeDate={handleChangeDate}
setFilters={setFilters}
filters={filters}
/>
);
}

Calendar with Custom Event Component

import WPCalendar from 'components/CalendarV2';

function CustomEventCalendar() {
const CustomEvent = ({ event }) => (
<Box
p={1}
borderRadius='md'
bg={getEventColor(event.status)}
color='white'
fontSize='xs'
>
<HStack spacing={1}>
<Avatar size='2xs' src={event.data?.profile_picture} />
<Text isTruncated>{event.title}</Text>
</HStack>
</Box>
);

return (
<WPCalendar
events={events}
loading={loading}
views={['month']}
components={{
event: CustomEvent,
}}
// ... other props
/>
);
}

WPCalendarToolbar

Calendar toolbar component providing navigation controls, view selection, and filtering options. Available in both V1 and V2 variants.

Component Location

// V1 Toolbar
import WPCalendarToolbar from 'components/Calendar/WPCalendarToolbar';

// V2 Toolbar
import WPCalendarToolbar from 'components/CalendarV2/WPCalendarToolbar';

V1 Toolbar Props

PropTypeRequiredDefaultDescription
labelstring-Calendar title/label
viewstring-Current view mode
viewsarray-Available views
onViewfunction-View change handler
onNavigatefunction-Navigation handler
showViewsboolean-trueShow view selector
showTodayboolean-trueShow today button
pagestring--Page context
colorDescarray--Color legend

V2 Toolbar Props (Extended)

Includes all V1 props plus:

PropTypeRequiredDefaultDescription
handleResetFiltersfunction-Reset filters handler
searchTextstring-Search input value
setSearchTextfunction-Search text setter
LeaveStatusOptionarray-Status filter options
leaveStatusstring-Current status filter
handleLeaveStatusFilterfunction-Status filter handler
handleChangeDatefunction-Date picker handler
goToViewfunction-View navigation
dateDate-Current date
filtersobject-Current filters
setFiltersfunction-Filters setter

Features

  • Previous/Next: Navigate between time periods
  • Today Button: Jump to current date
  • Date Label: Display current period

View Management

  • View Selector: Switch between month/week/day views
  • View State: Maintain selected view

Filtering (V2 Only)

  • Search Input: Text-based filtering
  • Status Dropdown: Filter by status
  • Date Picker: Select specific dates
  • Reset Filters: Clear all filters

Visual Elements

  • Color Legend: Status color indicators
  • Responsive Layout: Adapt to screen sizes

Usage Examples

Basic V1 Toolbar

import WPCalendarToolbar from 'components/Calendar/WPCalendarToolbar';

function CalendarWithToolbar() {
const [view, setView] = useState('month');
const [date, setDate] = useState(new Date());

const handleNavigate = action => {
// Handle navigation logic
switch (action) {
case 'PREV':
// Go to previous period
break;
case 'NEXT':
// Go to next period
break;
case 'TODAY':
setDate(new Date());
break;
}
};

const handleViewChange = newView => {
setView(newView);
};

return (
<WPCalendarToolbar
label='January 2024'
view={view}
views={['month', 'week', 'day']}
onView={handleViewChange}
onNavigate={handleNavigate}
showViews={true}
showToday={true}
/>
);
}

Advanced V2 Toolbar with Filtering

import WPCalendarToolbar from 'components/CalendarV2/WPCalendarToolbar';

function AdvancedToolbar() {
const [searchText, setSearchText] = useState('');
const [leaveStatus, setLeaveStatus] = useState('');
const [filters, setFilters] = useState({});

const statusOptions = [
{ value: 'APPROVED', label: 'Approved' },
{ value: 'PENDING', label: 'Pending' },
{ value: 'REJECTED', label: 'Rejected' },
];

return (
<WPCalendarToolbar
// Basic props
label='January 2024'
view='month'
views={['month', 'week', 'day']}
onView={handleViewChange}
onNavigate={handleNavigate}
// V2 filtering props
handleResetFilters={() => {
setSearchText('');
setLeaveStatus('');
setFilters({});
}}
searchText={searchText}
setSearchText={setSearchText}
LeaveStatusOption={statusOptions}
leaveStatus={leaveStatus}
handleLeaveStatusFilter={option => setLeaveStatus(option.value)}
handleChangeDate={date => setFilters({ ...filters, date })}
goToView={handleViewChange}
date={new Date()}
filters={filters}
setFilters={setFilters}
/>
);
}

EventPopup

Modal component for displaying detailed event information in Calendar V2.

Component Location

import EventPopup from 'components/CalendarV2/EventPopUp';

Props

PropTypeRequiredDefaultDescription
isOpenboolean-Modal open state
onClosefunction-Modal close handler
eventsEvent/Event[]-Event data (single or array)

TypeScript Interface

interface EventPopupProps {
isOpen: boolean;
onClose: () => void;
events: Event | Event[] | null;
}

interface Event {
title: string;
start: Date;
end: Date;
status: string;
type: string;
data: {
profile_picture?: string;
leave_type_name?: string;
[key: string]: any;
};
}

Features

Event Display Modes

  • Single Event: Detailed view of one event
  • Multiple Events: List view for multiple events on same day
  • Holiday Filtering: Excludes holiday events

Event Information

  • User Avatar: Employee profile picture
  • Event Title: Employee name or event title
  • Date Range: Formatted start and end dates
  • Leave Type: Type of leave or event
  • Status Indicator: Visual status representation

Status-based Styling

  • Color Coding: Different colors for different statuses
  • Background Colors: Status-specific backgrounds
  • Visual Hierarchy: Clear information organization

Status Color Mapping

const getBackgroundColor = (status: string) => {
switch (status) {
case 'NOT_APPROVED':
case 'APPROVED':
return 'hue-chrome.100';
case 'ACTIVE':
return 'hue-green.100';
case 'INACTIVE':
return 'skeletonTable';
case 'SCHEDULED':
return 'hue-sea.100';
default:
return 'transparent';
}
};

Usage Examples

Basic Event Popup

import EventPopup from 'components/CalendarV2/EventPopUp';
import { useDisclosure } from '@chakra-ui/react';

function CalendarWithPopup() {
const { isOpen, onOpen, onClose } = useDisclosure();
const [selectedEvent, setSelectedEvent] = useState(null);

const handleEventSelect = event => {
setSelectedEvent(event);
onOpen();
};

const handleShowMore = events => {
setSelectedEvent(events);
onOpen();
};

return (
<>
<WPCalendar
events={events}
onSelectEvent={handleEventSelect}
onShowMore={handleShowMore}
// ... other props
/>

<EventPopup isOpen={isOpen} onClose={onClose} events={selectedEvent} />
</>
);
}

Event Popup with Custom Handling

function CustomEventPopup() {
const [eventDetails, setEventDetails] = useState(null);
const { isOpen, onOpen, onClose } = useDisclosure();

const handleEventClick = event => {
if (event.type === 'holiday') {
// Don't show popup for holidays
return;
}

setEventDetails(event);
onOpen();
};

const handlePopupClose = () => {
setEventDetails(null);
onClose();
};

return (
<EventPopup
isOpen={isOpen}
onClose={handlePopupClose}
events={eventDetails}
/>
);
}

Calendar Integration Patterns

Full Calendar Implementation

import WPCalendar from 'components/CalendarV2';
import EventPopup from 'components/CalendarV2/EventPopUp';

function CompleteCalendarSystem() {
// State management
const [events, setEvents] = useState([]);
const [loading, setLoading] = useState(false);
const [filters, setFilters] = useState({});
const [selectedEvent, setSelectedEvent] = useState(null);

// Modal control
const { isOpen, onOpen, onClose } = useDisclosure();

// Event handlers
const handleEventSelect = event => {
setSelectedEvent(event);
onOpen();
};

const handleShowMore = events => {
setSelectedEvent(events);
onOpen();
};

const handleResetFilters = () => {
setFilters({});
// Reload data with cleared filters
loadEvents();
};

// Data loading
const loadEvents = useCallback(async () => {
setLoading(true);
try {
const data = await fetchEvents(filters);
setEvents(data);
} finally {
setLoading(false);
}
}, [filters]);

useEffect(() => {
loadEvents();
}, [loadEvents]);

return (
&lt;Box&gt;
<WPCalendar
events={events}
loading={loading}
views={['month', 'week', 'day']}
viewDate={new Date()}
eventPropGetter={eventPropGetter}
components={{}}
handleResetFilters={handleResetFilters}
searchText={filters.search || ''}
setSearchText={text => setFilters({ ...filters, search: text })}
LeaveStatusOption={statusOptions}
leaveStatus={filters.status || ''}
handleLeaveStatusFilter={option =>
setFilters({ ...filters, status: option.value })
}
handleChangeDate={date => setFilters({ ...filters, date })}
setFilters={setFilters}
filters={filters}
onSelectEvent={handleEventSelect}
onShowMore={handleShowMore}
/>

<EventPopup isOpen={isOpen} onClose={onClose} events={selectedEvent} />
</Box>
);
}

Event Data Structure

// Standard event structure for WorkPay calendars
interface CalendarEvent {
id: string;
title: string; // Employee name or event title
start: Date; // Event start date/time
end: Date; // Event end date/time
type: string; // 'leave' | 'meeting' | 'holiday' | 'overtime'
status: string; // 'APPROVED' | 'PENDING' | 'REJECTED' | 'ACTIVE' | 'INACTIVE'
data: {
employee_id?: string;
profile_picture?: string;
leave_type_name?: string;
department?: string;
manager?: string;
comments?: string;
[key: string]: any;
};
}

// Example events array
const sampleEvents: CalendarEvent[] = [
{
id: '1',
title: 'John Doe',
start: new Date('2024-01-15'),
end: new Date('2024-01-17'),
type: 'leave',
status: 'APPROVED',
data: {
employee_id: '123',
profile_picture: '/avatars/john.jpg',
leave_type_name: 'Annual Leave',
department: 'Engineering',
},
},
{
id: '2',
title: 'Team Meeting',
start: new Date('2024-01-20T10:00:00'),
end: new Date('2024-01-20T11:00:00'),
type: 'meeting',
status: 'SCHEDULED',
data: {
meeting_room: 'Conference Room A',
attendees: ['john@example.com', 'jane@example.com'],
},
},
];

Styling and Customization

CSS Customization

Both calendar versions include custom CSS files for styling:

V1 Calendar Styles

/* components/Calendar/calendar.css */
.rbc-calendar {
background: white;
border-radius: 8px;
}

.rbc-event {
border-radius: 4px;
padding: 2px 5px;
}

.rbc-month-view {
border: 1px solid #e2e8f0;
}

V2 Calendar Styles

/* components/CalendarV2/calendar.css */
.rbc-calendar {
height: 94vh;
font-family: inherit;
}

.rbc-today {
background-color: #f9fafa;
}

.rbc-event {
border-radius: 8px;
font-size: 12px;
}

Event Styling Patterns

// Common event styling function
const getEventStyle = (event, start, end, isSelected) => {
const baseStyle = {
borderRadius: '8px',
opacity: 0.9,
color: 'white',
border: 'none',
fontSize: '12px',
padding: '2px 6px',
};

// Status-based colors
const statusColors = {
APPROVED: '#38a169', // Green
PENDING: '#ecc94b', // Yellow
REJECTED: '#f56565', // Red
ACTIVE: '#3182ce', // Blue
INACTIVE: '#a0aec0', // Gray
SCHEDULED: '#9f7aea', // Purple
};

return {
style: {
...baseStyle,
backgroundColor: statusColors[event.status] || '#3174ad',
},
};
};

Responsive Design

// Responsive calendar container
function ResponsiveCalendar() {
return (
<Box
height={{ base: '70vh', md: '80vh', lg: '90vh' }}
overflowX='auto'
bg='white'
borderRadius='lg'
shadow='sm'
>
<WPCalendar
events={events}
views={['month']} // Only month view on mobile
// ... other props
/>
</Box>
);
}

Performance Optimization

Event Data Optimization

// Memoize event prop getter for performance
const eventPropGetter = useCallback((event, start, end, isSelected) => {
return getEventStyle(event, start, end, isSelected);
}, []);

// Memoize event data processing
const processedEvents = useMemo(() => {
return rawEvents.map(event => ({
...event,
start: new Date(event.start_date),
end: new Date(event.end_date),
}));
}, [rawEvents]);

Virtual Scrolling

// For large datasets, implement virtual scrolling
function OptimizedCalendar({ events }) {
const visibleEvents = useMemo(() => {
const currentMonth = new Date().getMonth();
return events.filter(
event => new Date(event.start).getMonth() === currentMonth,
);
}, [events]);

return (
<WPCalendar
events={visibleEvents}
// ... other props
/>
);
}

Accessibility

Keyboard Navigation

// Calendar with keyboard support
function AccessibleCalendar() {
const handleKeyDown = event => {
switch (event.key) {
case 'ArrowLeft':
// Navigate to previous day/week/month
break;
case 'ArrowRight':
// Navigate to next day/week/month
break;
case 'Enter':
case ' ':
// Select event or date
break;
case 'Escape':
// Close popups
break;
}
};

return (
<Box onKeyDown={handleKeyDown} tabIndex={0}>
<WPCalendar {...props} />
</Box>
);
}

Screen Reader Support

// Enhanced accessibility labels
function AccessibleEventPopup({ events }) {
const getAriaLabel = event => {
if (Array.isArray(event)) {
return `${event.length} events on ${format(
event[0].start,
'MMMM dd, yyyy',
)}`;
}
return `${event.title} leave from ${format(
event.start,
'MMMM dd',
)} to ${format(event.end, 'MMMM dd')}`;
};

return (
<Modal isOpen={isOpen} onClose={onClose} aria-label={getAriaLabel(events)}>
{/* Modal content */}
</Modal>
);
}

Testing Strategies

Unit Testing

import { render, screen, fireEvent } from '@testing-library/react';
import WPCalendar from 'components/CalendarV2';

describe('WPCalendar', () => {
const mockProps = {
events: [
{
id: '1',
title: 'Test Event',
start: new Date('2024-01-15'),
end: new Date('2024-01-16'),
status: 'APPROVED',
type: 'leave',
data: {},
},
],
loading: false,
views: ['month'],
eventPropGetter: jest.fn(),
components: {},
handleResetFilters: jest.fn(),
searchText: '',
setSearchText: jest.fn(),
LeaveStatusOption: [],
leaveStatus: '',
handleLeaveStatusFilter: jest.fn(),
handleChangeDate: jest.fn(),
setFilters: jest.fn(),
filters: {},
};

it('renders calendar with events', () => {
render(<WPCalendar {...mockProps} />);

expect(screen.getByText('Test Event')).toBeInTheDocument();
});

it('handles event selection', () => {
const onSelectEvent = jest.fn();
render(<WPCalendar {...mockProps} onSelectEvent={onSelectEvent} />);

fireEvent.click(screen.getByText('Test Event'));
expect(onSelectEvent).toHaveBeenCalledWith(mockProps.events[0]);
});

it('shows loading state', () => {
render(<WPCalendar {...mockProps} loading={true} />);

expect(screen.getByTestId('calendar-skeleton')).toBeInTheDocument();
});
});

Integration Testing

// Test complete calendar workflow
describe('Calendar Integration', () => {
it('filters events by status', async () => {
render(<CompleteCalendarSystem />);

// Select status filter
fireEvent.click(screen.getByText('Status Filter'));
fireEvent.click(screen.getByText('Approved'));

// Verify only approved events are shown
await waitFor(() => {
expect(screen.queryByText('Pending Event')).not.toBeInTheDocument();
expect(screen.getByText('Approved Event')).toBeInTheDocument();
});
});

it('opens event popup on click', async () => {
render(<CompleteCalendarSystem />);

fireEvent.click(screen.getByText('Test Event'));

await waitFor(() => {
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByText('Event Details')).toBeInTheDocument();
});
});
});

Migration Guide

V1 to V2 Migration

Update Imports

// Old V1 import
import WPCalendar from 'components/Calendar';

// New V2 import
import WPCalendar from 'components/CalendarV2';

Update Props Structure

// V1 props (minimal)
<WPCalendar
events={events}
loading={loading}
onSelectEvent={handleEventSelect}
/>

// V2 props (extended)
<WPCalendar
events={events}
loading={loading}
views={['month', 'week']}
eventPropGetter={eventPropGetter}
components={{}}
handleResetFilters={handleResetFilters}
searchText={searchText}
setSearchText={setSearchText}
LeaveStatusOption={statusOptions}
leaveStatus={leaveStatus}
handleLeaveStatusFilter={handleStatusFilter}
handleChangeDate={handleDateChange}
setFilters={setFilters}
filters={filters}
/>

Add Event Popup

// Add event popup for V2
import EventPopup from 'components/CalendarV2/EventPopUp';

function MigratedCalendar() {
const [selectedEvent, setSelectedEvent] = useState(null);
const { isOpen, onOpen, onClose } = useDisclosure();

return (
<>
<WPCalendar
onSelectEvent={event => {
setSelectedEvent(event);
onOpen();
}}
onShowMore={events => {
setSelectedEvent(events);
onOpen();
}}
// ... other props
/>

<EventPopup isOpen={isOpen} onClose={onClose} events={selectedEvent} />
</>
);
}

Breaking Changes

  1. Required Props: V2 requires more props for filtering functionality
  2. Event Structure: Enhanced event data structure with status and data fields
  3. Styling: Different CSS classes and styling approach
  4. Event Handling: Additional event handlers for popup and filtering

Best Practices

Calendar Implementation

  • Choose the right version: Use V2 for new implementations with filtering needs
  • Optimize event data: Process events efficiently for better performance
  • Handle loading states: Always provide loading indicators
  • Implement error boundaries: Handle calendar errors gracefully

Event Management

  • Consistent event structure: Follow the standard event interface
  • Status-based styling: Use consistent colors for event statuses
  • Accessibility: Provide proper labels and keyboard navigation
  • Mobile optimization: Ensure calendar works well on mobile devices

Performance

  • Memoize callbacks: Use useCallback for event handlers
  • Optimize re-renders: Minimize unnecessary component re-renders
  • Lazy load: Load events for visible time periods only
  • Cache data: Cache frequently accessed event data

User Experience

  • Clear navigation: Provide intuitive navigation controls
  • Responsive design: Ensure calendar adapts to screen sizes
  • Loading feedback: Show loading states during data fetching
  • Error handling: Display helpful error messages

This comprehensive calendar system provides robust scheduling and event management capabilities for the WorkPayCore Frontend application, with options for both basic and advanced use cases.