@umituz/react-native-design-system 2.3.13 → 2.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Calendar Events Service
3
+ *
4
+ * Handles CRUD operations for calendar events.
5
+ *
6
+ * SOLID: Single Responsibility - Only event operations
7
+ * DRY: Centralized event management
8
+ * KISS: Simple event interface
9
+ */
10
+
11
+ import * as Calendar from 'expo-calendar';
12
+ import { Platform } from 'react-native';
13
+ import { DateUtilities } from '../utils/DateUtilities';
14
+ import { CalendarPermissions } from './CalendarPermissions';
15
+ import type { CalendarEvent, SystemCalendar } from '../../domain/entities/CalendarEvent.entity';
16
+
17
+ export class CalendarEvents {
18
+ /**
19
+ * Create event in system calendar
20
+ */
21
+ static async createEvent(
22
+ event: CalendarEvent,
23
+ calendar: SystemCalendar
24
+ ): Promise<{ success: boolean; eventId?: string; error?: string }> {
25
+ try {
26
+ if (Platform.OS === 'web') {
27
+ return { success: false, error: 'Calendar sync not supported on web' };
28
+ }
29
+
30
+ const permission = await CalendarPermissions.requestPermissions();
31
+ if (!permission.granted) {
32
+ return { success: false, error: 'Calendar permission not granted' };
33
+ }
34
+
35
+ const eventData = this.buildEventData(event);
36
+ const systemEventId = await Calendar.createEventAsync(calendar.id, eventData);
37
+
38
+ return {
39
+ success: true,
40
+ eventId: systemEventId
41
+ };
42
+ } catch (error) {
43
+ return {
44
+ success: false,
45
+ error: error instanceof Error ? error.message : 'Failed to create event'
46
+ };
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Update event in system calendar
52
+ */
53
+ static async updateEvent(
54
+ event: CalendarEvent
55
+ ): Promise<{ success: boolean; error?: string }> {
56
+ try {
57
+ if (Platform.OS === 'web' || !event.systemCalendar?.eventId) {
58
+ return { success: false, error: 'No system calendar data' };
59
+ }
60
+
61
+ const permission = await CalendarPermissions.requestPermissions();
62
+ if (!permission.granted) {
63
+ return { success: false, error: 'Calendar permission not granted' };
64
+ }
65
+
66
+ const eventData = this.buildEventData(event);
67
+ await Calendar.updateEventAsync(event.systemCalendar.eventId, eventData);
68
+
69
+ return { success: true };
70
+ } catch (error) {
71
+ return {
72
+ success: false,
73
+ error: error instanceof Error ? error.message : 'Failed to update event'
74
+ };
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Delete event from system calendar
80
+ */
81
+ static async deleteEvent(
82
+ eventId: string
83
+ ): Promise<{ success: boolean; error?: string }> {
84
+ try {
85
+ if (Platform.OS === 'web') {
86
+ return { success: false, error: 'Calendar sync not supported on web' };
87
+ }
88
+
89
+ const permission = await CalendarPermissions.requestPermissions();
90
+ if (!permission.granted) {
91
+ return { success: false, error: 'Calendar permission not granted' };
92
+ }
93
+
94
+ await Calendar.deleteEventAsync(eventId);
95
+ return { success: true };
96
+ } catch (error) {
97
+ return {
98
+ success: false,
99
+ error: error instanceof Error ? error.message : 'Failed to delete event'
100
+ };
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Get events from system calendar
106
+ */
107
+ static async getSystemEvents(
108
+ calendarId: string,
109
+ startDate: Date,
110
+ endDate: Date
111
+ ): Promise<CalendarEvent[]> {
112
+ try {
113
+ if (Platform.OS === 'web') {
114
+ return [];
115
+ }
116
+
117
+ const permission = await CalendarPermissions.hasPermissions();
118
+ if (!permission) {
119
+ return [];
120
+ }
121
+
122
+ const systemEvents = await Calendar.getEventsAsync(
123
+ [calendarId],
124
+ startDate,
125
+ endDate
126
+ );
127
+
128
+ return systemEvents.map((event: Calendar.Event) => this.mapSystemEventToCalendarEvent(event));
129
+ } catch {
130
+ return [];
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Build event data for system calendar
136
+ */
137
+ private static buildEventData(event: CalendarEvent) {
138
+ const [year, month, day] = event.date.split('-').map(Number);
139
+ let startDate = new Date(year, month - 1, day);
140
+ let endDate = new Date(startDate);
141
+
142
+ // Set time if provided
143
+ if (event.time) {
144
+ const [hours, minutes] = event.time.split(':').map(Number);
145
+ startDate.setHours(hours, minutes, 0, 0);
146
+ endDate.setHours(hours, minutes, 0, 0);
147
+ }
148
+
149
+ // Set duration
150
+ if (event.duration) {
151
+ endDate.setMinutes(endDate.getMinutes() + event.duration);
152
+ } else {
153
+ endDate.setHours(endDate.getHours() + 1); // Default 1 hour
154
+ }
155
+
156
+ // Create reminders
157
+ const alarms = event.reminders?.map(minutesBefore => ({
158
+ relativeOffset: -minutesBefore
159
+ }));
160
+
161
+ return {
162
+ title: event.title,
163
+ startDate,
164
+ endDate,
165
+ notes: event.description,
166
+ location: event.location,
167
+ alarms,
168
+ timeZone: DateUtilities.getCurrentTimezone()
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Map system calendar event to domain event
174
+ */
175
+ private static mapSystemEventToCalendarEvent(systemEvent: any): CalendarEvent {
176
+ return {
177
+ id: systemEvent.id,
178
+ title: systemEvent.title || '',
179
+ description: systemEvent.notes || '',
180
+ date: DateUtilities.formatDateToString(systemEvent.startDate),
181
+ time: DateUtilities.formatTimeToString(systemEvent.startDate),
182
+ duration: systemEvent.endDate && systemEvent.startDate
183
+ ? (systemEvent.endDate.getTime() - systemEvent.startDate.getTime()) / (1000 * 60)
184
+ : undefined,
185
+ location: systemEvent.location || '',
186
+ reminders: systemEvent.alarms?.map((alarm: any) => -alarm.relativeOffset) || [],
187
+ createdAt: new Date(),
188
+ updatedAt: new Date(),
189
+ systemCalendar: {
190
+ calendarId: systemEvent.calendarId,
191
+ eventId: systemEvent.id,
192
+ lastSyncedAt: new Date()
193
+ }
194
+ };
195
+ }
196
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Calendar Generation Service
3
+ *
4
+ * Generates calendar grids and layouts.
5
+ *
6
+ * SOLID: Single Responsibility - Only calendar generation
7
+ * DRY: Reusable calendar generation logic
8
+ * KISS: Simple calendar grid creation
9
+ */
10
+
11
+ import { DateUtilities } from '../utils/DateUtilities';
12
+ import type { CalendarDay } from '../../domain/entities/CalendarDay.entity';
13
+ import type { CalendarEvent } from '../../domain/entities/CalendarEvent.entity';
14
+
15
+ export class CalendarGeneration {
16
+ /**
17
+ * Generate calendar days for a specific month
18
+ * Returns 42 days (6 weeks) including days from prev/next months
19
+ */
20
+ static generateMonthDays(
21
+ year: number,
22
+ month: number,
23
+ events: CalendarEvent[] = []
24
+ ): CalendarDay[] {
25
+ const firstDay = new Date(year, month, 1);
26
+ const startDate = new Date(firstDay);
27
+
28
+ // Start from Sunday of the week containing the 1st
29
+ startDate.setDate(startDate.getDate() - firstDay.getDay());
30
+
31
+ const days: CalendarDay[] = [];
32
+ const today = new Date();
33
+
34
+ // Generate 42 days (6 weeks)
35
+ for (let i = 0; i < 42; i++) {
36
+ const currentDate = DateUtilities.addDays(startDate, i);
37
+ const dayEvents = this.getEventsForDate(currentDate, events);
38
+
39
+ days.push({
40
+ date: currentDate,
41
+ isCurrentMonth: currentDate.getMonth() === month,
42
+ isToday: DateUtilities.isSameDay(currentDate, today),
43
+ isSelected: false,
44
+ events: dayEvents
45
+ });
46
+ }
47
+
48
+ return days;
49
+ }
50
+
51
+ /**
52
+ * Generate calendar days for a specific week
53
+ */
54
+ static generateWeekDays(
55
+ startDate: Date,
56
+ events: CalendarEvent[] = []
57
+ ): CalendarDay[] {
58
+ const days: CalendarDay[] = [];
59
+ const today = new Date();
60
+
61
+ for (let i = 0; i < 7; i++) {
62
+ const currentDate = DateUtilities.addDays(startDate, i);
63
+ const dayEvents = this.getEventsForDate(currentDate, events);
64
+
65
+ days.push({
66
+ date: currentDate,
67
+ isCurrentMonth: true, // All days in week view are "current"
68
+ isToday: DateUtilities.isSameDay(currentDate, today),
69
+ isSelected: false,
70
+ events: dayEvents
71
+ });
72
+ }
73
+
74
+ return days;
75
+ }
76
+
77
+ /**
78
+ * Get events for a specific date
79
+ */
80
+ static getEventsForDate(date: Date, allEvents: CalendarEvent[]): CalendarEvent[] {
81
+ const dateStr = DateUtilities.formatDateToString(date);
82
+ return allEvents.filter(event => event.date === dateStr);
83
+ }
84
+
85
+ /**
86
+ * Get events in date range
87
+ */
88
+ static getEventsInRange(
89
+ startDate: Date,
90
+ endDate: Date,
91
+ events: CalendarEvent[]
92
+ ): CalendarEvent[] {
93
+ const startStr = DateUtilities.formatDateToString(startDate);
94
+ const endStr = DateUtilities.formatDateToString(endDate);
95
+
96
+ return events.filter(event => event.date >= startStr && event.date <= endStr);
97
+ }
98
+
99
+ /**
100
+ * Navigate to previous month
101
+ */
102
+ static getPreviousMonth(currentDate: Date): Date {
103
+ const newDate = new Date(currentDate);
104
+ newDate.setMonth(newDate.getMonth() - 1);
105
+ return newDate;
106
+ }
107
+
108
+ /**
109
+ * Navigate to next month
110
+ */
111
+ static getNextMonth(currentDate: Date): Date {
112
+ const newDate = new Date(currentDate);
113
+ newDate.setMonth(newDate.getMonth() + 1);
114
+ return newDate;
115
+ }
116
+
117
+ /**
118
+ * Navigate to previous week
119
+ */
120
+ static getPreviousWeek(currentDate: Date): Date {
121
+ return DateUtilities.addDays(currentDate, -7);
122
+ }
123
+
124
+ /**
125
+ * Navigate to next week
126
+ */
127
+ static getNextWeek(currentDate: Date): Date {
128
+ return DateUtilities.addDays(currentDate, 7);
129
+ }
130
+
131
+ /**
132
+ * Check if date is today
133
+ */
134
+ static isToday(date: Date): boolean {
135
+ return DateUtilities.isToday(date);
136
+ }
137
+
138
+ /**
139
+ * Check if two dates are the same day
140
+ */
141
+ static isSameDay(date1: Date, date2: Date): boolean {
142
+ return DateUtilities.isSameDay(date1, date2);
143
+ }
144
+
145
+ /**
146
+ * Format date for display
147
+ */
148
+ static formatDate(date: Date): string {
149
+ return DateUtilities.formatDateToString(date);
150
+ }
151
+
152
+ /**
153
+ * Get month name
154
+ */
155
+ static getMonthName(date: Date): string {
156
+ return date.toLocaleDateString('en-US', { month: 'long' });
157
+ }
158
+
159
+ /**
160
+ * Get weekday name
161
+ */
162
+ static getWeekdayName(date: Date): string {
163
+ return date.toLocaleDateString('en-US', { weekday: 'long' });
164
+ }
165
+
166
+ /**
167
+ * Get short weekday name
168
+ */
169
+ static getShortWeekdayName(date: Date): string {
170
+ return date.toLocaleDateString('en-US', { weekday: 'short' });
171
+ }
172
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Calendar Permissions Service
3
+ *
4
+ * Handles calendar permission requests and status checks.
5
+ *
6
+ * SOLID: Single Responsibility - Only permission operations
7
+ * DRY: Centralized permission logic
8
+ * KISS: Simple permission interface
9
+ */
10
+
11
+ import * as Calendar from 'expo-calendar';
12
+ import { Platform } from 'react-native';
13
+ import type { CalendarPermissionResult } from '../../domain/entities/CalendarEvent.entity';
14
+
15
+ export class CalendarPermissions {
16
+ /**
17
+ * Request calendar permissions
18
+ *
19
+ * @returns Promise with permission result
20
+ */
21
+ static async requestPermissions(): Promise<CalendarPermissionResult> {
22
+ try {
23
+ if (Platform.OS === 'web') {
24
+ return {
25
+ granted: false,
26
+ canAskAgain: false,
27
+ status: 'denied'
28
+ };
29
+ }
30
+
31
+ const { status, canAskAgain } = await Calendar.requestCalendarPermissionsAsync();
32
+
33
+ return {
34
+ granted: status === 'granted',
35
+ canAskAgain,
36
+ status
37
+ };
38
+ } catch {
39
+ return {
40
+ granted: false,
41
+ canAskAgain: false,
42
+ status: 'error'
43
+ };
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Check if calendar permissions are granted
49
+ *
50
+ * @returns Promise with permission status
51
+ */
52
+ static async hasPermissions(): Promise<boolean> {
53
+ try {
54
+ if (Platform.OS === 'web') {
55
+ return false;
56
+ }
57
+
58
+ const { status } = await Calendar.getCalendarPermissionsAsync();
59
+ return status === 'granted';
60
+ } catch {
61
+ return false;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Get current permission status
67
+ *
68
+ * @returns Promise with current status
69
+ */
70
+ static async getPermissionStatus(): Promise<CalendarPermissionResult['status']> {
71
+ try {
72
+ if (Platform.OS === 'web') {
73
+ return 'denied';
74
+ }
75
+
76
+ const { status } = await Calendar.getCalendarPermissionsAsync();
77
+ return status;
78
+ } catch {
79
+ return 'error';
80
+ }
81
+ }
82
+ }
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Calendar Service
3
+ *
4
+ * Facade for calendar operations using composition.
5
+ * Delegates to specialized services for specific operations.
6
+ *
7
+ * SOLID: Facade pattern - Single entry point, delegates to specialists
8
+ * DRY: Avoids code duplication by composing smaller services
9
+ * KISS: Simple interface, complex operations delegated
10
+ */
11
+
12
+ import type { CalendarDay, CalendarWeek } from '../../domain/entities/CalendarDay.entity';
13
+ import type { CalendarEvent, SystemCalendar } from '../../domain/entities/CalendarEvent.entity';
14
+ import { CalendarGeneration } from './CalendarGeneration';
15
+ import { CalendarPermissions } from './CalendarPermissions';
16
+ // CalendarEvents is not used in this facade
17
+ // import { CalendarEvents } from './CalendarEvents';
18
+ import { CalendarSync } from './CalendarSync';
19
+ import { DateUtilities } from '../utils/DateUtilities';
20
+
21
+ /**
22
+ * Calendar Service Implementation
23
+ *
24
+ * Facade that delegates to specialized services.
25
+ * Follows SOLID principles with composition over inheritance.
26
+ */
27
+ export class CalendarService {
28
+ /**
29
+ * Generate calendar days for a specific month
30
+ */
31
+ static getMonthDays(
32
+ year: number,
33
+ month: number,
34
+ events: CalendarEvent[] = []
35
+ ): CalendarDay[] {
36
+ return CalendarGeneration.generateMonthDays(year, month, events);
37
+ }
38
+
39
+ /**
40
+ * Generate calendar week
41
+ */
42
+ static getWeek(date: Date, events: CalendarEvent[] = []): CalendarWeek {
43
+ const startDate = DateUtilities.getStartOfWeek(date);
44
+ const endDate = DateUtilities.getEndOfWeek(date);
45
+ const days = CalendarGeneration.generateWeekDays(startDate, events);
46
+
47
+ return {
48
+ startDate,
49
+ endDate,
50
+ days
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Navigate to previous month
56
+ */
57
+ static getPreviousMonth(currentDate: Date): Date {
58
+ return CalendarGeneration.getPreviousMonth(currentDate);
59
+ }
60
+
61
+ /**
62
+ * Navigate to next month
63
+ */
64
+ static getNextMonth(currentDate: Date): Date {
65
+ return CalendarGeneration.getNextMonth(currentDate);
66
+ }
67
+
68
+ /**
69
+ * Navigate to previous week
70
+ */
71
+ static getPreviousWeek(currentDate: Date): Date {
72
+ return CalendarGeneration.getPreviousWeek(currentDate);
73
+ }
74
+
75
+ /**
76
+ * Navigate to next week
77
+ */
78
+ static getNextWeek(currentDate: Date): Date {
79
+ return CalendarGeneration.getNextWeek(currentDate);
80
+ }
81
+
82
+ /**
83
+ * Request calendar permissions
84
+ */
85
+ static async requestPermissions() {
86
+ return CalendarPermissions.requestPermissions();
87
+ }
88
+
89
+ /**
90
+ * Check if permissions are granted
91
+ */
92
+ static async hasPermissions(): Promise<boolean> {
93
+ return CalendarPermissions.hasPermissions();
94
+ }
95
+
96
+ /**
97
+ * Sync event to system calendar
98
+ */
99
+ static async syncToSystemCalendar(event: CalendarEvent) {
100
+ return CalendarSync.syncToSystemCalendar(event);
101
+ }
102
+
103
+ /**
104
+ * Update system calendar event
105
+ */
106
+ static async updateSystemCalendarEvent(event: CalendarEvent) {
107
+ return CalendarSync.updateSystemCalendarEvent(event);
108
+ }
109
+
110
+ /**
111
+ * Remove event from system calendar
112
+ */
113
+ static async removeFromSystemCalendar(eventId: string) {
114
+ return CalendarSync.removeFromSystemCalendar(eventId);
115
+ }
116
+
117
+ /**
118
+ * Get system calendars
119
+ */
120
+ static async getSystemCalendars(): Promise<SystemCalendar[]> {
121
+ return CalendarSync.getSystemCalendars();
122
+ }
123
+
124
+ /**
125
+ * Get events for a specific date
126
+ */
127
+ static getEventsForDate(date: Date, events: CalendarEvent[]): CalendarEvent[] {
128
+ return CalendarGeneration.getEventsForDate(date, events);
129
+ }
130
+
131
+ /**
132
+ * Get events in date range
133
+ */
134
+ static getEventsInRange(
135
+ startDate: Date,
136
+ endDate: Date,
137
+ events: CalendarEvent[]
138
+ ): CalendarEvent[] {
139
+ return CalendarGeneration.getEventsInRange(startDate, endDate, events);
140
+ }
141
+
142
+ /**
143
+ * Get weekday names
144
+ */
145
+ static getWeekdayNames(): string[] {
146
+ const weekdays: string[] = [];
147
+ for (let i = 0; i < 7; i++) {
148
+ const date = new Date();
149
+ date.setDate(date.getDate() - date.getDay() + i);
150
+ weekdays.push(date.toLocaleDateString('en-US', { weekday: 'short' }));
151
+ }
152
+ return weekdays;
153
+ }
154
+
155
+ /**
156
+ * Check if two dates are the same day
157
+ */
158
+ static isSameDay(date1: Date, date2: Date): boolean {
159
+ return DateUtilities.isSameDay(date1, date2);
160
+ }
161
+ }