Calendar
A sophisticated React Native calendar component with infinite scrolling, pinch-to-zoom functionality, and real-time event management. Built with React Native Reanimated for smooth animations and optimized performance.
๐ Features
- Infinite Scrolling: Seamlessly navigate through dates with edge loading
- Pinch-to-Zoom: Adjust time scale from 0.5x to 3x with smooth animations
- Real-time Current Time Indicator: Shows current time with live updates
- Event Management: Display events with custom colors and time ranges
- Month Picker Modal: Quick date selection with month/year navigation
- Responsive Design: Adapts to different screen sizes and orientations
- Performance Optimized: Uses React.memo, useCallback, and efficient re-renders
- TypeScript Support: Full type safety with comprehensive interfaces
๐ Project Structure
booking-planner/
โโโ components/
โ โโโ DayColumn.tsx # Individual day column component
โ โโโ EventBlock.tsx # Event display component
โ โโโ HourGridRow.tsx # Hour grid row component
โ โโโ MonthPicker.tsx # Month picker modal
โ โโโ TimeLabel.tsx # Time label component
โโโ constants/
โ โโโ index.ts # App constants and sample events
โโโ hooks/
โ โโโ useCalendarData.ts # Calendar data management hook
โโโ types/
โ โโโ index.ts # TypeScript interfaces
โโโ utils/
โ โโโ index.ts # Utility functions
โโโ _layout.tsx # Navigation layout
โโโ index.tsx # Main calendar component
โโโ README.md
๐ ๏ธ Setup Instructions
1. Prerequisites
Ensure you have the following dependencies in your package.json:
{
"dependencies": {
"react-native-reanimated": "^3.0.0",
"react-native-gesture-handler": "^2.0.0",
"@expo/vector-icons": "^13.0.0",
"@react-navigation/drawer": "^6.0.0"
}
}2. Context Setup
Wrap your app with the CalendarProvider:
// App.tsx or your root component
import { CalendarProvider } from '@/contexts/CalendarContext';
export default function App() {
return (
<CalendarProvider>
{/* Your app components */}
</CalendarProvider>
);
}3. Navigation Integration
Add the calendar to your navigation stack:
// In your navigation configuration
import BookingPlanner from '@/app/booking-planner/index';
// Add to your stack navigator
<Stack.Screen name="booking-planner" component={BookingPlanner} />Or navigate to the route directly:
// Navigate to the booking planner
navigation.navigate('booking-planner');4. Gesture Handler Setup
Ensure GestureHandlerRootView wraps your app:
import { GestureHandlerRootView } from 'react-native-gesture-handler';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<CalendarProvider>
{/* Your app */}
</CalendarProvider>
</GestureHandlerRootView>
);
}๐ฏ Core Components
Main Calendar (index.tsx)
The main calendar component that orchestrates all functionality:
- Infinite Scrolling: Loads days dynamically as user scrolls
- Pinch Gesture: Handles zoom functionality with
Gesture.Pinch() - Synchronized Scrolling: Keeps header and body in sync
- Current Time Indicator: Shows live current time position
Event Management
Events are defined with the following interface:
interface EventItem {
id: string;
title: string;
date: string; // YYYY-MM-DD format
start: string; // HH:mm format
end: string; // HH:mm format
color: string; // Hex color code
}Data Hook (useCalendarData.ts)
Manages calendar state and data loading:
- Day Generation: Creates date ranges for infinite scrolling
- Event Filtering: Filters events by date
- Loading States: Handles future/past day loading
- Date Selection: Manages selected and viewing dates
๐จ Customization
Constants Configuration
Modify constants/index.ts to customize:
export const DEFAULT_CELL_HEIGHT = 60; // Default hour height
export const MIN_SCALE = 0.5; // Minimum zoom level
export const MAX_SCALE = 3; // Maximum zoom level
export const TIME_COLUMN_WIDTH = 60; // Time column width
export const ALL_DAY_HEIGHT = 40; // All-day section heightEvent Colors
Update the SAMPLE_EVENTS array in constants/index.ts:
export const SAMPLE_EVENTS = [
{
id: '1',
title: 'Meeting',
date: '2025-01-15',
start: '09:00',
end: '10:00',
color: '#FFDAD2', // Custom color
},
// ... more events
];Styling
Customize component styles in their respective files:
EventBlock.tsx: Event appearance and layoutTimeLabel.tsx: Time label stylingDayColumn.tsx: Day column appearanceMonthPicker.tsx: Month picker modal styling
๐ง Advanced Usage
Custom Event Rendering
Override the default event rendering:
// In your calendar component
const renderEvent = useCallback((event: EventItem) => (
<CustomEventBlock
event={event}
cellHeightSV={cellHeight}
/>
), [cellHeight]);Custom Data Source
Replace the sample events with your data source:
// In useCalendarData.ts
const getEventsByDayCallback = useCallback(
(d: Date) => getEventsByDay(YOUR_EVENTS_DATA, d),
[]
);Calendar Context Integration
Access calendar state from anywhere:
import { useCalendar } from '@/contexts/CalendarContext';
function MyComponent() {
const { numberOfDays, setNumberOfDays } = useCalendar();
// Change view (1, 3, 7 days)
const changeView = (days: number) => {
setNumberOfDays(days);
};
}๐ฎ User Interactions
Navigation
- Horizontal Swipe: Navigate between days
- Pinch Gesture: Zoom in/out of time scale
- Tap Events: Select events (customize in EventBlock)
- Month Picker: Tap header date to open month picker
Gestures
- Pinch: Adjust time scale (0.5x - 3x)
- Scroll: Infinite day navigation
- Tap: Event selection and date picking
๐ฑ Performance Optimizations
React.memo Usage
All components are wrapped with React.memo for efficient re-renders.
Shared Values
Uses useSharedValue for smooth animations:
cellHeight: Controls zoom levelminutesSV: Tracks current timebaseScale: Manages pinch gesture
Efficient Rendering
FlatListwithgetItemLayoutfor predictable scrollinginitialNumToRenderandmaxToRenderPerBatchoptimizationremoveClippedSubviewsfor memory management
๐ Troubleshooting
Common Issues
-
Gesture Handler Not Working
- Ensure
GestureHandlerRootViewwraps your app - Check gesture handler installation
- Ensure
-
Animations Not Smooth
- Verify Reanimated 3.x installation
- Check for conflicting gesture handlers
-
Events Not Displaying
- Verify event date format (YYYY-MM-DD)
- Check time format (HH:mm)
- Ensure events array is properly structured
-
Performance Issues
- Implement virtual scrolling for large datasets
- Use
React.memofor custom components
Debug Mode
Enable debug logging by adding console logs in key functions:
// In useCalendarData.ts
const loadDaysAround = useCallback((anchor: Date) => {
console.log('Loading days around:', anchor);
// ... existing code
}, []);๐ License
This component is part of the landingcomponents.com library.