@umituz/react-native-calendar
Version:
Generic calendar component for React Native apps with timezone support, event management, and system calendar sync
197 lines (174 loc) • 5.57 kB
text/typescript
/**
* Calendar Events Service
*
* Handles CRUD operations for calendar events.
*
* SOLID: Single Responsibility - Only event operations
* DRY: Centralized event management
* KISS: Simple event interface
*/
import * as Calendar from 'expo-calendar';
import { Platform } from 'react-native';
import { DateUtilities } from '../utils/DateUtilities';
import { CalendarPermissions } from './CalendarPermissions';
import type { CalendarEvent, SystemCalendar } from '../../domain/entities/CalendarEvent.entity';
export class CalendarEvents {
/**
* Create event in system calendar
*/
static async createEvent(
event: CalendarEvent,
calendar: SystemCalendar
): Promise<{ success: boolean; eventId?: string; error?: string }> {
try {
if (Platform.OS === 'web') {
return { success: false, error: 'Calendar sync not supported on web' };
}
const permission = await CalendarPermissions.requestPermissions();
if (!permission.granted) {
return { success: false, error: 'Calendar permission not granted' };
}
const eventData = this.buildEventData(event);
const systemEventId = await Calendar.createEventAsync(calendar.id, eventData);
return {
success: true,
eventId: systemEventId
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to create event'
};
}
}
/**
* Update event in system calendar
*/
static async updateEvent(
event: CalendarEvent
): Promise<{ success: boolean; error?: string }> {
try {
if (Platform.OS === 'web' || !event.systemCalendar?.eventId) {
return { success: false, error: 'No system calendar data' };
}
const permission = await CalendarPermissions.requestPermissions();
if (!permission.granted) {
return { success: false, error: 'Calendar permission not granted' };
}
const eventData = this.buildEventData(event);
await Calendar.updateEventAsync(event.systemCalendar.eventId, eventData);
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to update event'
};
}
}
/**
* Delete event from system calendar
*/
static async deleteEvent(
eventId: string
): Promise<{ success: boolean; error?: string }> {
try {
if (Platform.OS === 'web') {
return { success: false, error: 'Calendar sync not supported on web' };
}
const permission = await CalendarPermissions.requestPermissions();
if (!permission.granted) {
return { success: false, error: 'Calendar permission not granted' };
}
await Calendar.deleteEventAsync(eventId);
return { success: true };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to delete event'
};
}
}
/**
* Get events from system calendar
*/
static async getSystemEvents(
calendarId: string,
startDate: Date,
endDate: Date
): Promise<CalendarEvent[]> {
try {
if (Platform.OS === 'web') {
return [];
}
const permission = await CalendarPermissions.hasPermissions();
if (!permission) {
return [];
}
const systemEvents = await Calendar.getEventsAsync(
[calendarId],
startDate,
endDate
);
return systemEvents.map(event => this.mapSystemEventToCalendarEvent(event));
} catch (error) {
return [];
}
}
/**
* Build event data for system calendar
*/
private static buildEventData(event: CalendarEvent) {
const [year, month, day] = event.date.split('-').map(Number);
let startDate = new Date(year, month - 1, day);
let endDate = new Date(startDate);
// Set time if provided
if (event.time) {
const [hours, minutes] = event.time.split(':').map(Number);
startDate.setHours(hours, minutes, 0, 0);
endDate.setHours(hours, minutes, 0, 0);
}
// Set duration
if (event.duration) {
endDate.setMinutes(endDate.getMinutes() + event.duration);
} else {
endDate.setHours(endDate.getHours() + 1); // Default 1 hour
}
// Create reminders
const alarms = event.reminders?.map(minutesBefore => ({
relativeOffset: -minutesBefore
}));
return {
title: event.title,
startDate,
endDate,
notes: event.description,
location: event.location,
alarms,
timeZone: DateUtilities.getCurrentTimezone()
};
}
/**
* Map system calendar event to domain event
*/
private static mapSystemEventToCalendarEvent(systemEvent: any): CalendarEvent {
return {
id: systemEvent.id,
title: systemEvent.title || '',
description: systemEvent.notes || '',
date: DateUtilities.formatDateToString(systemEvent.startDate),
time: DateUtilities.formatTimeToString(systemEvent.startDate),
duration: systemEvent.endDate && systemEvent.startDate
? (systemEvent.endDate.getTime() - systemEvent.startDate.getTime()) / (1000 * 60)
: undefined,
location: systemEvent.location || '',
reminders: systemEvent.alarms?.map((alarm: any) => -alarm.relativeOffset) || [],
createdAt: new Date(),
updatedAt: new Date(),
systemCalendar: {
calendarId: systemEvent.calendarId,
eventId: systemEvent.id,
lastSyncedAt: new Date()
}
};
}
}