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
- WPCalendar (V1) - Legacy calendar implementation
- WPCalendar (V2) - Enhanced calendar with advanced features
- WPCalendarToolbar - Calendar navigation and controls
- EventPopup - Event details modal (V2 only)
Integration Components
- DatePicker Components - Date selection inputs
- Filter Components - Calendar filtering controls
WPCalendar (V1)
The legacy calendar implementation providing basic calendar functionality with event display and navigation.
Component Location
import WPCalendar from 'components/Calendar';
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| events | object | ✓ | - | Calendar events data |
| loading | boolean | ✓ | - | Loading state indicator |
| views | array | - | ['month'] | Available calendar views |
| viewDate | Date | - | new Date() | Initial calendar date |
| onSelectEvent | function | - | - | Event selection handler |
| tooltipAccessor | string | - | '' | Tooltip data accessor |
| onShowMore | function | - | - | Show more events handler |
| eventPropGetter | function | - | - | Event styling function |
| showAllEvents | boolean | - | false | Show all events flag |
| components | object | - | - | Custom component overrides |
| showToday | boolean | - | true | Show today button |
| showViews | boolean | - | true | Show view selector |
| page | string | - | - | Page context for styling |
| colorDesc | array | - | - | 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<any>;
[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
Navigation
- 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
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| events | Event[] | ✓ | - | Calendar events array |
| loading | boolean | ✓ | - | Loading state indicator |
| views | array | ✓ | - | Available calendar views |
| viewDate | Date | - | new Date() | Initial calendar date |
| eventPropGetter | function | ✓ | - | Event styling function |
| components | object | ✓ | - | Custom component overrides |
| handleResetFilters | function | ✓ | - | Reset filters handler |
| searchText | string | ✓ | - | Search text value |
| setSearchText | function | ✓ | - | Search text setter |
| LeaveStatusOption | array | ✓ | - | Leave status options |
| leaveStatus | string | ✓ | - | Current leave status |
| handleLeaveStatusFilter | function | ✓ | - | Status filter handler |
| handleChangeDate | function | ✓ | - | Date change handler |
| setFilters | function | ✓ | - | Filters setter |
| filters | object | ✓ | - | 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
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| label | string | ✓ | - | Calendar title/label |
| view | string | ✓ | - | Current view mode |
| views | array | ✓ | - | Available views |
| onView | function | ✓ | - | View change handler |
| onNavigate | function | ✓ | - | Navigation handler |
| showViews | boolean | - | true | Show view selector |
| showToday | boolean | - | true | Show today button |
| page | string | - | - | Page context |
| colorDesc | array | - | - | Color legend |
V2 Toolbar Props (Extended)
Includes all V1 props plus:
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| handleResetFilters | function | ✓ | - | Reset filters handler |
| searchText | string | ✓ | - | Search input value |
| setSearchText | function | ✓ | - | Search text setter |
| LeaveStatusOption | array | ✓ | - | Status filter options |
| leaveStatus | string | ✓ | - | Current status filter |
| handleLeaveStatusFilter | function | ✓ | - | Status filter handler |
| handleChangeDate | function | ✓ | - | Date picker handler |
| goToView | function | ✓ | - | View navigation |
| date | Date | ✓ | - | Current date |
| filters | object | ✓ | - | Current filters |
| setFilters | function | ✓ | - | Filters setter |
Features
Navigation Controls
- 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
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| isOpen | boolean | ✓ | - | Modal open state |
| onClose | function | ✓ | - | Modal close handler |
| events | Event/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 (
<Box>
<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
- Required Props: V2 requires more props for filtering functionality
- Event Structure: Enhanced event data structure with status and data fields
- Styling: Different CSS classes and styling approach
- 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.