@umituz/react-native-design-system 2.6.62 → 2.6.64
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.
- package/package.json +1 -1
- package/src/atoms/AtomicIcon.tsx +2 -6
- package/src/atoms/AtomicIcon.types.ts +5 -0
- package/src/atoms/AtomicInput.tsx +34 -154
- package/src/atoms/AtomicPicker.tsx +31 -123
- package/src/atoms/index.ts +6 -4
- package/src/atoms/input/components/InputHelper.tsx +49 -0
- package/src/atoms/input/components/InputIcon.tsx +44 -0
- package/src/atoms/input/components/InputLabel.tsx +20 -0
- package/src/atoms/input/styles/inputStylesHelper.ts +1 -1
- package/src/atoms/input/types.ts +72 -0
- package/src/atoms/picker/hooks/usePickerState.ts +139 -0
- package/src/exports/atoms.ts +69 -0
- package/src/exports/device.ts +58 -0
- package/src/exports/layouts.ts +19 -0
- package/src/exports/molecules.ts +166 -0
- package/src/exports/organisms.ts +9 -0
- package/src/exports/responsive.ts +36 -0
- package/src/exports/safe-area.ts +6 -0
- package/src/exports/theme.ts +47 -0
- package/src/exports/typography.ts +22 -0
- package/src/exports/utilities.ts +6 -0
- package/src/exports/variants.ts +22 -0
- package/src/index.ts +11 -417
- package/src/molecules/avatar/Avatar.constants.ts +103 -0
- package/src/molecules/avatar/Avatar.types.ts +64 -0
- package/src/molecules/avatar/Avatar.utils.ts +8 -160
- package/src/molecules/calendar/index.ts +4 -9
- package/src/molecules/calendar/infrastructure/storage/CalendarStore.ts +103 -302
- package/src/molecules/calendar/infrastructure/storage/CalendarStore.ts.bak +116 -0
- package/src/molecules/calendar/infrastructure/storage/CalendarStore.types.ts +64 -0
- package/src/molecules/calendar/infrastructure/storage/CalendarStore.utils.ts +56 -0
- package/src/molecules/calendar/infrastructure/storage/EventActions.ts +140 -0
- package/src/molecules/calendar/infrastructure/storage/NavigationActions.ts +118 -0
- package/src/molecules/calendar/infrastructure/stores/storageAdapter.ts +34 -0
- package/src/molecules/calendar/infrastructure/stores/useCalendarEvents.ts +168 -0
- package/src/molecules/calendar/infrastructure/stores/useCalendarNavigation.ts +47 -0
- package/src/molecules/calendar/infrastructure/stores/useCalendarView.ts +24 -0
- package/src/molecules/calendar/presentation/hooks/useCalendar.ts +7 -11
- package/src/responsive/compute/computeDeviceInfo.ts +22 -0
- package/src/responsive/compute/computeResponsivePositioning.ts +42 -0
- package/src/responsive/compute/computeResponsiveSizes.ts +48 -0
- package/src/responsive/padding/paddingUtils.ts +65 -0
- package/src/responsive/positioning/positioningUtils.ts +61 -0
- package/src/responsive/responsiveLayout.ts +11 -264
- package/src/responsive/screen/screenLayoutConfig.ts +38 -0
- package/src/responsive/tabbar/tabBarConfig.ts +88 -0
- package/src/responsive/types/responsiveTypes.ts +69 -0
- package/src/responsive/useResponsive.ts +69 -158
|
@@ -1,153 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Avatar
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Supports images, initials, icons with Turkish character support.
|
|
2
|
+
* Avatar Utilities
|
|
3
|
+
* Utility class for avatar operations
|
|
4
|
+
* Supports images, initials, icons with Turkish character support
|
|
6
5
|
*/
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*/
|
|
11
|
-
export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Avatar shape
|
|
15
|
-
*/
|
|
16
|
-
export type AvatarShape = 'circle' | 'square' | 'rounded';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Avatar type
|
|
20
|
-
*/
|
|
21
|
-
export type AvatarType = 'image' | 'initials' | 'icon';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Avatar configuration
|
|
25
|
-
*/
|
|
26
|
-
export interface AvatarConfig {
|
|
27
|
-
/** Avatar type */
|
|
28
|
-
type: AvatarType;
|
|
29
|
-
/** Size preset */
|
|
30
|
-
size: AvatarSize;
|
|
31
|
-
/** Shape */
|
|
32
|
-
shape: AvatarShape;
|
|
33
|
-
/** Image URI */
|
|
34
|
-
uri?: string;
|
|
35
|
-
/** User name for initials */
|
|
36
|
-
name?: string;
|
|
37
|
-
/** Icon name (if type is icon) */
|
|
38
|
-
icon?: string;
|
|
39
|
-
/** Custom background color */
|
|
40
|
-
backgroundColor?: string;
|
|
41
|
-
/** Show status indicator */
|
|
42
|
-
showStatus?: boolean;
|
|
43
|
-
/** Status (online/offline) */
|
|
44
|
-
status?: 'online' | 'offline' | 'away' | 'busy';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Size configuration
|
|
49
|
-
*/
|
|
50
|
-
export interface SizeConfig {
|
|
51
|
-
size: number;
|
|
52
|
-
fontSize: number;
|
|
53
|
-
iconSize: number;
|
|
54
|
-
statusSize: number;
|
|
55
|
-
borderWidth: number;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Avatar group configuration
|
|
60
|
-
*/
|
|
61
|
-
export interface AvatarGroupConfig {
|
|
62
|
-
maxVisible: number;
|
|
63
|
-
spacing: number;
|
|
64
|
-
size: AvatarSize;
|
|
65
|
-
shape: AvatarShape;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Size configurations (px)
|
|
70
|
-
*/
|
|
71
|
-
export const SIZE_CONFIGS: Record<AvatarSize, SizeConfig> = {
|
|
72
|
-
xs: {
|
|
73
|
-
size: 24,
|
|
74
|
-
fontSize: 10,
|
|
75
|
-
iconSize: 12,
|
|
76
|
-
statusSize: 6,
|
|
77
|
-
borderWidth: 1,
|
|
78
|
-
},
|
|
79
|
-
sm: {
|
|
80
|
-
size: 32,
|
|
81
|
-
fontSize: 12,
|
|
82
|
-
iconSize: 16,
|
|
83
|
-
statusSize: 8,
|
|
84
|
-
borderWidth: 1.5,
|
|
85
|
-
},
|
|
86
|
-
md: {
|
|
87
|
-
size: 40,
|
|
88
|
-
fontSize: 14,
|
|
89
|
-
iconSize: 20,
|
|
90
|
-
statusSize: 10,
|
|
91
|
-
borderWidth: 2,
|
|
92
|
-
},
|
|
93
|
-
lg: {
|
|
94
|
-
size: 56,
|
|
95
|
-
fontSize: 18,
|
|
96
|
-
iconSize: 28,
|
|
97
|
-
statusSize: 12,
|
|
98
|
-
borderWidth: 2,
|
|
99
|
-
},
|
|
100
|
-
xl: {
|
|
101
|
-
size: 80,
|
|
102
|
-
fontSize: 24,
|
|
103
|
-
iconSize: 40,
|
|
104
|
-
statusSize: 16,
|
|
105
|
-
borderWidth: 2.5,
|
|
106
|
-
},
|
|
107
|
-
xxl: {
|
|
108
|
-
size: 120,
|
|
109
|
-
fontSize: 36,
|
|
110
|
-
iconSize: 60,
|
|
111
|
-
statusSize: 20,
|
|
112
|
-
borderWidth: 3,
|
|
113
|
-
},
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Avatar background colors
|
|
118
|
-
* Vibrant, accessible colors with good contrast
|
|
119
|
-
*/
|
|
120
|
-
export const AVATAR_COLORS = [
|
|
121
|
-
'#EF4444', // Red
|
|
122
|
-
'#F59E0B', // Orange
|
|
123
|
-
'#10B981', // Green
|
|
124
|
-
'#3B82F6', // Blue
|
|
125
|
-
'#8B5CF6', // Purple
|
|
126
|
-
'#EC4899', // Pink
|
|
127
|
-
'#14B8A6', // Teal
|
|
128
|
-
'#F97316', // Orange-Red
|
|
129
|
-
'#06B6D4', // Cyan
|
|
130
|
-
'#84CC16', // Lime
|
|
131
|
-
] as const;
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Status indicator colors
|
|
135
|
-
*/
|
|
136
|
-
export const STATUS_COLORS = {
|
|
137
|
-
online: '#10B981', // Green
|
|
138
|
-
offline: '#9CA3AF', // Gray
|
|
139
|
-
away: '#F59E0B', // Orange
|
|
140
|
-
busy: '#EF4444', // Red
|
|
141
|
-
} as const;
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Border radius configurations
|
|
145
|
-
*/
|
|
146
|
-
export const SHAPE_CONFIGS = {
|
|
147
|
-
circle: 9999, // Full circle
|
|
148
|
-
square: 0, // No radius
|
|
149
|
-
rounded: 8, // Rounded corners
|
|
150
|
-
} as const;
|
|
7
|
+
import type { AvatarSize, AvatarShape, AvatarConfig, SizeConfig } from './Avatar.types';
|
|
8
|
+
import { AVATAR_COLORS, STATUS_COLORS, SHAPE_CONFIGS, SIZE_CONFIGS } from './Avatar.constants';
|
|
151
9
|
|
|
152
10
|
/**
|
|
153
11
|
* Avatar utility class
|
|
@@ -275,16 +133,6 @@ export class AvatarUtils {
|
|
|
275
133
|
}
|
|
276
134
|
}
|
|
277
135
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
export const AVATAR_CONSTANTS = {
|
|
282
|
-
DEFAULT_SIZE: 'md' as AvatarSize,
|
|
283
|
-
DEFAULT_SHAPE: 'circle' as AvatarShape,
|
|
284
|
-
DEFAULT_TYPE: 'initials' as AvatarType,
|
|
285
|
-
DEFAULT_ICON: 'user',
|
|
286
|
-
MAX_GROUP_VISIBLE: 3,
|
|
287
|
-
GROUP_SPACING: -8, // Negative for overlap
|
|
288
|
-
FALLBACK_INITIALS: '?',
|
|
289
|
-
} as const;
|
|
290
|
-
|
|
136
|
+
// Re-export types and constants for convenience
|
|
137
|
+
export type { AvatarSize, AvatarShape, AvatarType, AvatarConfig, SizeConfig } from './Avatar.types';
|
|
138
|
+
export { AVATAR_COLORS, STATUS_COLORS, SHAPE_CONFIGS, SIZE_CONFIGS, AVATAR_CONSTANTS } from './Avatar.constants';
|
|
@@ -54,18 +54,13 @@ export { CalendarGeneration } from './infrastructure/services/CalendarGeneration
|
|
|
54
54
|
export { DateUtilities } from './infrastructure/utils/DateUtilities';
|
|
55
55
|
|
|
56
56
|
// Infrastructure Storage
|
|
57
|
-
export {
|
|
58
|
-
useCalendarStore,
|
|
59
|
-
type CalendarViewMode,
|
|
60
|
-
} from './infrastructure/storage/CalendarStore';
|
|
61
|
-
|
|
62
|
-
// Presentation Hooks
|
|
63
57
|
export {
|
|
64
58
|
useCalendar,
|
|
65
|
-
useCalendarNavigation,
|
|
66
59
|
useCalendarEvents,
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
useCalendarNavigation,
|
|
61
|
+
useCalendarView,
|
|
62
|
+
type CalendarViewMode,
|
|
63
|
+
} from './infrastructure/storage/CalendarStore';
|
|
69
64
|
|
|
70
65
|
// Presentation Components
|
|
71
66
|
export {
|
|
@@ -1,315 +1,116 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Calendar Store
|
|
3
|
-
*
|
|
4
|
-
* Global state management for calendar functionality.
|
|
5
|
-
* Manages calendar view state, selected date, and events.
|
|
6
|
-
*
|
|
7
|
-
* Design Philosophy:
|
|
8
|
-
* - Zustand for lightweight state
|
|
9
|
-
* - AsyncStorage for persistence
|
|
10
|
-
* - Generic event handling
|
|
11
|
-
* - Timezone-aware via CalendarService
|
|
2
|
+
* Calendar Store - Combined Hook
|
|
3
|
+
* Convenience hook that combines all calendar stores
|
|
12
4
|
*/
|
|
13
5
|
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import
|
|
18
|
-
import { CalendarService } from '
|
|
6
|
+
import { useMemo } from 'react';
|
|
7
|
+
import { useCalendarEvents } from '../stores/useCalendarEvents';
|
|
8
|
+
import { useCalendarNavigation } from '../stores/useCalendarNavigation';
|
|
9
|
+
import { useCalendarView } from '../stores/useCalendarView';
|
|
10
|
+
import { CalendarService } from '../../../services/CalendarService';
|
|
11
|
+
import type { CalendarDay } from '../../../domain/entities/CalendarDay.entity';
|
|
19
12
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export
|
|
13
|
+
// Export individual stores
|
|
14
|
+
export { useCalendarEvents } from '../stores/useCalendarEvents';
|
|
15
|
+
export { useCalendarNavigation } from '../stores/useCalendarNavigation';
|
|
16
|
+
export { useCalendarView } from '../stores/useCalendarView';
|
|
24
17
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
*/
|
|
28
|
-
const STORAGE_KEY = 'calendar_events';
|
|
18
|
+
// Export types
|
|
19
|
+
export type { CalendarViewMode } from '../stores/useCalendarView';
|
|
29
20
|
|
|
30
21
|
/**
|
|
31
|
-
*
|
|
22
|
+
* Combined calendar hook
|
|
23
|
+
* Use this for convenience, or use individual stores for fine-grained control
|
|
32
24
|
*/
|
|
33
|
-
const
|
|
34
|
-
|
|
25
|
+
export const useCalendar = () => {
|
|
26
|
+
const events = useCalendarEvents();
|
|
27
|
+
const navigation = useCalendarNavigation();
|
|
28
|
+
const view = useCalendarView();
|
|
29
|
+
|
|
30
|
+
// Utility functions for backward compatibility
|
|
31
|
+
const getEventsForDate = (date: Date) => {
|
|
32
|
+
return events.events.filter(event => {
|
|
33
|
+
const eventDate = new Date(event.date);
|
|
34
|
+
return eventDate.toDateString() === date.toDateString();
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const getEventsForMonth = (year: number, month: number) => {
|
|
39
|
+
return events.events.filter(event => {
|
|
40
|
+
const eventDate = new Date(event.date);
|
|
41
|
+
return eventDate.getFullYear() === year && eventDate.getMonth() === month;
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
// Events state and actions
|
|
47
|
+
events: events.events,
|
|
48
|
+
isLoading: events.isLoading,
|
|
49
|
+
error: events.error,
|
|
50
|
+
loadEvents: events.loadEvents,
|
|
51
|
+
addEvent: events.addEvent,
|
|
52
|
+
updateEvent: events.updateEvent,
|
|
53
|
+
deleteEvent: events.deleteEvent,
|
|
54
|
+
completeEvent: events.completeEvent,
|
|
55
|
+
uncompleteEvent: events.uncompleteEvent,
|
|
56
|
+
clearError: events.clearError,
|
|
57
|
+
clearAllEvents: events.clearAllEvents,
|
|
58
|
+
|
|
59
|
+
// Navigation state and actions
|
|
60
|
+
selectedDate: navigation.selectedDate,
|
|
61
|
+
currentMonth: navigation.currentMonth,
|
|
62
|
+
setSelectedDate: navigation.setSelectedDate,
|
|
63
|
+
goToToday: navigation.goToToday,
|
|
64
|
+
navigateMonth: navigation.navigateMonth,
|
|
65
|
+
setCurrentMonth: navigation.setCurrentMonth,
|
|
66
|
+
|
|
67
|
+
// View state and actions
|
|
68
|
+
viewMode: view.viewMode,
|
|
69
|
+
setViewMode: view.setViewMode,
|
|
70
|
+
|
|
71
|
+
// Utility functions
|
|
72
|
+
getEventsForDate,
|
|
73
|
+
getEventsForMonth,
|
|
74
|
+
};
|
|
35
75
|
};
|
|
36
76
|
|
|
37
77
|
/**
|
|
38
|
-
*
|
|
39
|
-
|
|
40
|
-
interface CalendarState {
|
|
41
|
-
events: CalendarEvent[];
|
|
42
|
-
selectedDate: Date;
|
|
43
|
-
currentMonth: Date;
|
|
44
|
-
viewMode: CalendarViewMode;
|
|
45
|
-
isLoading: boolean;
|
|
46
|
-
error: string | null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Calendar actions
|
|
51
|
-
*/
|
|
52
|
-
interface CalendarActions {
|
|
53
|
-
// Event CRUD
|
|
54
|
-
loadEvents: () => Promise<void>;
|
|
55
|
-
addEvent: (request: CreateCalendarEventRequest) => Promise<void>;
|
|
56
|
-
updateEvent: (request: UpdateCalendarEventRequest) => Promise<void>;
|
|
57
|
-
deleteEvent: (id: string) => Promise<void>;
|
|
58
|
-
completeEvent: (id: string) => Promise<void>;
|
|
59
|
-
uncompleteEvent: (id: string) => Promise<void>;
|
|
60
|
-
|
|
61
|
-
// Navigation
|
|
62
|
-
setSelectedDate: (date: Date) => void;
|
|
63
|
-
goToToday: () => void;
|
|
64
|
-
navigateMonth: (direction: 'prev' | 'next') => void;
|
|
65
|
-
navigateWeek: (direction: 'prev' | 'next') => void;
|
|
66
|
-
setCurrentMonth: (date: Date) => void;
|
|
67
|
-
|
|
68
|
-
// View mode
|
|
69
|
-
setViewMode: (mode: CalendarViewMode) => void;
|
|
70
|
-
|
|
71
|
-
// Utilities
|
|
72
|
-
getEventsForDate: (date: Date) => CalendarEvent[];
|
|
73
|
-
getEventsForMonth: (year: number, month: number) => CalendarEvent[];
|
|
74
|
-
clearError: () => void;
|
|
75
|
-
clearAllEvents: () => Promise<void>;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Initial state
|
|
78
|
+
* Legacy alias for backward compatibility
|
|
79
|
+
* @deprecated Use useCalendar instead
|
|
80
80
|
*/
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
export const useCalendarStore = () => {
|
|
82
|
+
const calendar = useCalendar();
|
|
83
|
+
|
|
84
|
+
const days = useMemo(() => {
|
|
85
|
+
const year = calendar.currentMonth.getFullYear();
|
|
86
|
+
const month = calendar.currentMonth.getMonth();
|
|
87
|
+
return CalendarService.getMonthDays(year, month, calendar.events);
|
|
88
|
+
}, [calendar.currentMonth, calendar.events]);
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
events: calendar.events,
|
|
92
|
+
selectedDate: calendar.selectedDate,
|
|
93
|
+
currentMonth: calendar.currentMonth,
|
|
94
|
+
viewMode: calendar.viewMode,
|
|
95
|
+
isLoading: calendar.isLoading,
|
|
96
|
+
error: calendar.error,
|
|
97
|
+
actions: {
|
|
98
|
+
loadEvents: calendar.loadEvents,
|
|
99
|
+
addEvent: calendar.addEvent,
|
|
100
|
+
updateEvent: calendar.updateEvent,
|
|
101
|
+
deleteEvent: calendar.deleteEvent,
|
|
102
|
+
completeEvent: calendar.completeEvent,
|
|
103
|
+
uncompleteEvent: calendar.uncompleteEvent,
|
|
104
|
+
setSelectedDate: calendar.setSelectedDate,
|
|
105
|
+
goToToday: calendar.goToToday,
|
|
106
|
+
navigateMonth: calendar.navigateMonth,
|
|
107
|
+
setCurrentMonth: calendar.setCurrentMonth,
|
|
108
|
+
setViewMode: calendar.setViewMode,
|
|
109
|
+
getEventsForDate: calendar.getEventsForDate,
|
|
110
|
+
getEventsForMonth: calendar.getEventsForMonth,
|
|
111
|
+
clearError: calendar.clearError,
|
|
112
|
+
clearAllEvents: calendar.clearAllEvents,
|
|
113
|
+
},
|
|
114
|
+
days,
|
|
115
|
+
};
|
|
88
116
|
};
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Calendar Store
|
|
92
|
-
*/
|
|
93
|
-
export const useCalendarStore = create<CalendarState & { actions: CalendarActions }>()(
|
|
94
|
-
persist(
|
|
95
|
-
(set, get) => ({
|
|
96
|
-
...initialState,
|
|
97
|
-
actions: {
|
|
98
|
-
/**
|
|
99
|
-
* Load events from storage
|
|
100
|
-
*/
|
|
101
|
-
loadEvents: async () => {
|
|
102
|
-
set({ isLoading: true, error: null });
|
|
103
|
-
try {
|
|
104
|
-
const result = await storageRepository.getItem<CalendarEvent[]>(STORAGE_KEY, []);
|
|
105
|
-
const events = unwrap(result, []);
|
|
106
|
-
|
|
107
|
-
if (events && events.length > 0) {
|
|
108
|
-
// Restore Date objects
|
|
109
|
-
const hydratedEvents = events.map((event) => ({
|
|
110
|
-
...event,
|
|
111
|
-
createdAt: new Date(event.createdAt),
|
|
112
|
-
updatedAt: new Date(event.updatedAt),
|
|
113
|
-
}));
|
|
114
|
-
set({ events: hydratedEvents, isLoading: false });
|
|
115
|
-
} else {
|
|
116
|
-
set({ isLoading: false });
|
|
117
|
-
}
|
|
118
|
-
} catch {
|
|
119
|
-
set({
|
|
120
|
-
error: 'Failed to load events',
|
|
121
|
-
isLoading: false,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Add a new event
|
|
128
|
-
*/
|
|
129
|
-
addEvent: async (request: CreateCalendarEventRequest) => {
|
|
130
|
-
set({ isLoading: true, error: null });
|
|
131
|
-
try {
|
|
132
|
-
const newEvent: CalendarEvent = {
|
|
133
|
-
id: generateId(),
|
|
134
|
-
...request,
|
|
135
|
-
isCompleted: false,
|
|
136
|
-
createdAt: new Date(),
|
|
137
|
-
updatedAt: new Date(),
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const events = [...get().events, newEvent];
|
|
141
|
-
await storageRepository.setItem(STORAGE_KEY, events);
|
|
142
|
-
set({ events, isLoading: false });
|
|
143
|
-
} catch {
|
|
144
|
-
set({
|
|
145
|
-
error: 'Failed to add event',
|
|
146
|
-
isLoading: false,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Update an existing event
|
|
153
|
-
*/
|
|
154
|
-
updateEvent: async (request: UpdateCalendarEventRequest) => {
|
|
155
|
-
set({ isLoading: true, error: null });
|
|
156
|
-
try {
|
|
157
|
-
const events = get().events.map((event) => {
|
|
158
|
-
if (event.id === request.id) {
|
|
159
|
-
return {
|
|
160
|
-
...event,
|
|
161
|
-
...request,
|
|
162
|
-
updatedAt: new Date(),
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
return event;
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
await storageRepository.setItem(STORAGE_KEY, events);
|
|
169
|
-
set({ events, isLoading: false });
|
|
170
|
-
} catch {
|
|
171
|
-
set({
|
|
172
|
-
error: 'Failed to update event',
|
|
173
|
-
isLoading: false,
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Delete an event
|
|
180
|
-
*/
|
|
181
|
-
deleteEvent: async (id: string) => {
|
|
182
|
-
set({ isLoading: true, error: null });
|
|
183
|
-
try {
|
|
184
|
-
const events = get().events.filter((event) => event.id !== id);
|
|
185
|
-
await storageRepository.setItem(STORAGE_KEY, events);
|
|
186
|
-
set({ events, isLoading: false });
|
|
187
|
-
} catch {
|
|
188
|
-
set({
|
|
189
|
-
error: 'Failed to delete event',
|
|
190
|
-
isLoading: false,
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Mark event as completed
|
|
197
|
-
*/
|
|
198
|
-
completeEvent: async (id: string) => {
|
|
199
|
-
await get().actions.updateEvent({ id, isCompleted: true });
|
|
200
|
-
},
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Mark event as incomplete
|
|
204
|
-
*/
|
|
205
|
-
uncompleteEvent: async (id: string) => {
|
|
206
|
-
await get().actions.updateEvent({ id, isCompleted: false });
|
|
207
|
-
},
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Set selected date
|
|
211
|
-
*/
|
|
212
|
-
setSelectedDate: (date: Date) => {
|
|
213
|
-
set({ selectedDate: date });
|
|
214
|
-
},
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Go to today's date
|
|
218
|
-
*/
|
|
219
|
-
goToToday: () => {
|
|
220
|
-
const today = new Date();
|
|
221
|
-
set({
|
|
222
|
-
selectedDate: today,
|
|
223
|
-
currentMonth: today,
|
|
224
|
-
});
|
|
225
|
-
},
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Navigate to previous/next month
|
|
229
|
-
*/
|
|
230
|
-
navigateMonth: (direction: 'prev' | 'next') => {
|
|
231
|
-
const currentMonth = get().currentMonth;
|
|
232
|
-
const newMonth =
|
|
233
|
-
direction === 'prev'
|
|
234
|
-
? CalendarService.getPreviousMonth(currentMonth)
|
|
235
|
-
: CalendarService.getNextMonth(currentMonth);
|
|
236
|
-
|
|
237
|
-
set({ currentMonth: newMonth });
|
|
238
|
-
},
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Navigate to previous/next week
|
|
242
|
-
*/
|
|
243
|
-
navigateWeek: (direction: 'prev' | 'next') => {
|
|
244
|
-
const selectedDate = get().selectedDate;
|
|
245
|
-
const newDate =
|
|
246
|
-
direction === 'prev'
|
|
247
|
-
? CalendarService.getPreviousWeek(selectedDate)
|
|
248
|
-
: CalendarService.getNextWeek(selectedDate);
|
|
249
|
-
|
|
250
|
-
set({ selectedDate: newDate });
|
|
251
|
-
},
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Set current month directly
|
|
255
|
-
*/
|
|
256
|
-
setCurrentMonth: (date: Date) => {
|
|
257
|
-
set({ currentMonth: date });
|
|
258
|
-
},
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Set view mode
|
|
262
|
-
*/
|
|
263
|
-
setViewMode: (mode: CalendarViewMode) => {
|
|
264
|
-
set({ viewMode: mode });
|
|
265
|
-
},
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Get events for a specific date
|
|
269
|
-
*/
|
|
270
|
-
getEventsForDate: (date: Date) => {
|
|
271
|
-
const events = get().events;
|
|
272
|
-
return CalendarService.getEventsForDate(date, events);
|
|
273
|
-
},
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Get events for a specific month
|
|
277
|
-
*/
|
|
278
|
-
getEventsForMonth: (year: number, month: number) => {
|
|
279
|
-
const events = get().events;
|
|
280
|
-
const firstDay = new Date(year, month, 1);
|
|
281
|
-
const lastDay = new Date(year, month + 1, 0);
|
|
282
|
-
return CalendarService.getEventsInRange(firstDay, lastDay, events);
|
|
283
|
-
},
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Clear error state
|
|
287
|
-
*/
|
|
288
|
-
clearError: () => {
|
|
289
|
-
set({ error: null });
|
|
290
|
-
},
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Clear all events (for testing/reset)
|
|
294
|
-
*/
|
|
295
|
-
clearAllEvents: async () => {
|
|
296
|
-
set({ isLoading: true, error: null });
|
|
297
|
-
try {
|
|
298
|
-
await storageRepository.removeItem(STORAGE_KEY);
|
|
299
|
-
set({ events: [], isLoading: false });
|
|
300
|
-
} catch {
|
|
301
|
-
set({
|
|
302
|
-
error: 'Failed to clear events',
|
|
303
|
-
isLoading: false,
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
},
|
|
308
|
-
}),
|
|
309
|
-
{
|
|
310
|
-
name: 'calendar-storage',
|
|
311
|
-
storage: createJSONStorage(() => storageService),
|
|
312
|
-
partialize: (state) => ({ events: state.events }),
|
|
313
|
-
}
|
|
314
|
-
)
|
|
315
|
-
);
|